| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 /// A Shelf adapter for handling [HttpRequest] objects from `dart:io`. | 5 /// A Shelf adapter for handling [HttpRequest] objects from `dart:io`. |
| 6 /// | 6 /// |
| 7 /// One can provide an instance of [HttpServer] as the `requests` parameter in | 7 /// One can provide an instance of [HttpServer] as the `requests` parameter in |
| 8 /// [serveRequests]. | 8 /// [serveRequests]. |
| 9 /// | 9 /// |
| 10 /// The `dart:io` adapter supports request hijacking; see [Request.hijack]. | 10 /// This adapter supports request hijacking; see [Request.hijack]. It also |
| 11 /// supports the `"shelf.io.buffer_output"` `Response.context` property. If this |
| 12 /// property is `true` (the default), streamed responses will be buffered to |
| 13 /// improve performance; if it's `false`, all chunks will be pushed over the |
| 14 /// wire as they're received. See [`HttpResponse.bufferOutput`][bufferOutput] |
| 15 /// for more information. |
| 16 /// |
| 17 /// [bufferOutput]: https://api.dartlang.org/apidocs/channels/stable/dartdoc-vie
wer/dart:io.HttpResponse#id_bufferOutput |
| 11 library shelf.io; | 18 library shelf.io; |
| 12 | 19 |
| 13 import 'dart:async'; | 20 import 'dart:async'; |
| 14 import 'dart:io'; | 21 import 'dart:io'; |
| 15 | 22 |
| 16 import 'package:stack_trace/stack_trace.dart'; | 23 import 'package:stack_trace/stack_trace.dart'; |
| 17 | 24 |
| 18 import 'shelf.dart'; | 25 import 'shelf.dart'; |
| 19 import 'src/util.dart'; | 26 import 'src/util.dart'; |
| 20 | 27 |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 71 // If the request wasn't hijacked, we shouldn't be seeing this exception. | 78 // If the request wasn't hijacked, we shouldn't be seeing this exception. |
| 72 return _logError( | 79 return _logError( |
| 73 "Caught HijackException, but the request wasn't hijacked.", | 80 "Caught HijackException, but the request wasn't hijacked.", |
| 74 stackTrace); | 81 stackTrace); |
| 75 } | 82 } |
| 76 | 83 |
| 77 return _logError('Error thrown by handler.\n$error', stackTrace); | 84 return _logError('Error thrown by handler.\n$error', stackTrace); |
| 78 }).then((response) { | 85 }).then((response) { |
| 79 if (response == null) { | 86 if (response == null) { |
| 80 response = _logError('null response from handler.'); | 87 response = _logError('null response from handler.'); |
| 81 } else if (!shelfRequest.canHijack) { | 88 } else if (shelfRequest.canHijack) { |
| 82 var message = new StringBuffer() | 89 return _writeResponse(response, request.response); |
| 83 ..writeln("Got a response for hijacked request " | |
| 84 "${shelfRequest.method} ${shelfRequest.requestedUri}:") | |
| 85 ..writeln(response.statusCode); | |
| 86 response.headers | |
| 87 .forEach((key, value) => message.writeln("${key}: ${value}")); | |
| 88 throw new Exception(message.toString().trim()); | |
| 89 } | 90 } |
| 90 | 91 |
| 91 return _writeResponse(response, request.response); | 92 var message = new StringBuffer() |
| 93 ..writeln("Got a response for hijacked request " |
| 94 "${shelfRequest.method} ${shelfRequest.requestedUri}:") |
| 95 ..writeln(response.statusCode); |
| 96 response.headers |
| 97 .forEach((key, value) => message.writeln("${key}: ${value}")); |
| 98 throw new Exception(message.toString().trim()); |
| 92 }).catchError((error, stackTrace) { | 99 }).catchError((error, stackTrace) { |
| 93 // Ignore HijackExceptions. | 100 // Ignore HijackExceptions. |
| 94 if (error is! HijackException) throw error; | 101 if (error is! HijackException) throw error; |
| 95 }); | 102 }); |
| 96 } | 103 } |
| 97 | 104 |
| 98 /// Creates a new [Request] from the provided [HttpRequest]. | 105 /// Creates a new [Request] from the provided [HttpRequest]. |
| 99 Request _fromHttpRequest(HttpRequest request) { | 106 Request _fromHttpRequest(HttpRequest request) { |
| 100 var headers = {}; | 107 var headers = {}; |
| 101 request.headers.forEach((k, v) { | 108 request.headers.forEach((k, v) { |
| 102 // Multiple header values are joined with commas. | 109 // Multiple header values are joined with commas. |
| 103 // See http://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-21#page-22 | 110 // See http://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-21#page-22 |
| 104 headers[k] = v.join(','); | 111 headers[k] = v.join(','); |
| 105 }); | 112 }); |
| 106 | 113 |
| 107 onHijack(callback) { | 114 onHijack(callback) { |
| 108 return request.response | 115 return request.response |
| 109 .detachSocket(writeHeaders: false) | 116 .detachSocket(writeHeaders: false) |
| 110 .then((socket) => callback(socket, socket)); | 117 .then((socket) => callback(socket, socket)); |
| 111 } | 118 } |
| 112 | 119 |
| 113 return new Request(request.method, request.requestedUri, | 120 return new Request(request.method, request.requestedUri, |
| 114 protocolVersion: request.protocolVersion, | 121 protocolVersion: request.protocolVersion, |
| 115 headers: headers, | 122 headers: headers, |
| 116 body: request, | 123 body: request, |
| 117 onHijack: onHijack); | 124 onHijack: onHijack); |
| 118 } | 125 } |
| 119 | 126 |
| 120 Future _writeResponse(Response response, HttpResponse httpResponse) { | 127 Future _writeResponse(Response response, HttpResponse httpResponse) { |
| 128 if (response.context.containsKey("shelf.io.buffer_output")) { |
| 129 httpResponse.bufferOutput = response.context["shelf.io.buffer_output"]; |
| 130 } |
| 131 |
| 121 httpResponse.statusCode = response.statusCode; | 132 httpResponse.statusCode = response.statusCode; |
| 122 | 133 |
| 123 response.headers.forEach((header, value) { | 134 response.headers.forEach((header, value) { |
| 124 if (value == null) return; | 135 if (value == null) return; |
| 125 httpResponse.headers.set(header, value); | 136 httpResponse.headers.set(header, value); |
| 126 }); | 137 }); |
| 127 | 138 |
| 128 if (!response.headers.containsKey(HttpHeaders.SERVER)) { | 139 if (!response.headers.containsKey(HttpHeaders.SERVER)) { |
| 129 httpResponse.headers.set(HttpHeaders.SERVER, 'dart:io with Shelf'); | 140 httpResponse.headers.set(HttpHeaders.SERVER, 'dart:io with Shelf'); |
| 130 } | 141 } |
| (...skipping 15 matching lines...) Expand all Loading... |
| 146 chain = new Chain.forTrace(stackTrace); | 157 chain = new Chain.forTrace(stackTrace); |
| 147 } | 158 } |
| 148 chain = chain | 159 chain = chain |
| 149 .foldFrames((frame) => frame.isCore || frame.package == 'shelf').terse; | 160 .foldFrames((frame) => frame.isCore || frame.package == 'shelf').terse; |
| 150 | 161 |
| 151 stderr.writeln('ERROR - ${new DateTime.now()}'); | 162 stderr.writeln('ERROR - ${new DateTime.now()}'); |
| 152 stderr.writeln(message); | 163 stderr.writeln(message); |
| 153 stderr.writeln(chain); | 164 stderr.writeln(chain); |
| 154 return new Response.internalServerError(); | 165 return new Response.internalServerError(); |
| 155 } | 166 } |
| OLD | NEW |