Mercurial > projects > hoofbaby
comparison deps/Platinum/Source/Core/PltHttp.cpp @ 0:3425707ddbf6
Initial import (hopefully this mercurial stuff works...)
author | fraserofthenight |
---|---|
date | Mon, 06 Jul 2009 08:06:28 -0700 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:3425707ddbf6 |
---|---|
1 /***************************************************************** | |
2 | | |
3 | Platinum - HTTP Protocol Helper | |
4 | | |
5 | Copyright (c) 2004-2008, Plutinosoft, LLC. | |
6 | All rights reserved. | |
7 | http://www.plutinosoft.com | |
8 | | |
9 | This program is free software; you can redistribute it and/or | |
10 | modify it under the terms of the GNU General Public License | |
11 | as published by the Free Software Foundation; either version 2 | |
12 | of the License, or (at your option) any later version. | |
13 | | |
14 | OEMs, ISVs, VARs and other distributors that combine and | |
15 | distribute commercially licensed software with Platinum software | |
16 | and do not wish to distribute the source code for the commercially | |
17 | licensed software under version 2, or (at your option) any later | |
18 | version, of the GNU General Public License (the "GPL") must enter | |
19 | into a commercial license agreement with Plutinosoft, LLC. | |
20 | | |
21 | This program is distributed in the hope that it will be useful, | |
22 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
23 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
24 | GNU General Public License for more details. | |
25 | | |
26 | You should have received a copy of the GNU General Public License | |
27 | along with this program; see the file LICENSE.txt. If not, write to | |
28 | the Free Software Foundation, Inc., | |
29 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
30 | http://www.gnu.org/licenses/gpl-2.0.html | |
31 | | |
32 ****************************************************************/ | |
33 | |
34 /*---------------------------------------------------------------------- | |
35 | includes | |
36 +---------------------------------------------------------------------*/ | |
37 #include "PltHttp.h" | |
38 #include "PltDatagramStream.h" | |
39 #include "PltVersion.h" | |
40 | |
41 NPT_SET_LOCAL_LOGGER("platinum.core.http") | |
42 | |
43 /*---------------------------------------------------------------------- | |
44 | external references | |
45 +---------------------------------------------------------------------*/ | |
46 extern NPT_String HttpServerHeader; | |
47 | |
48 /*---------------------------------------------------------------------- | |
49 | NPT_HttpHeaderFinder | |
50 +---------------------------------------------------------------------*/ | |
51 class NPT_HttpHeaderFinder | |
52 { | |
53 public: | |
54 // methods | |
55 NPT_HttpHeaderFinder(const char* name) : m_Name(name) {} | |
56 bool operator()(const NPT_HttpHeader* const & header) const { | |
57 if (header->GetName().Compare(m_Name, true)) { | |
58 return true; | |
59 } else { | |
60 return false; | |
61 } | |
62 } | |
63 | |
64 private: | |
65 // members | |
66 NPT_String m_Name; | |
67 }; | |
68 | |
69 /*---------------------------------------------------------------------- | |
70 | NPT_HttpHeaderPrinter | |
71 +---------------------------------------------------------------------*/ | |
72 class NPT_HttpHeaderPrinter | |
73 { | |
74 public: | |
75 // methods | |
76 NPT_HttpHeaderPrinter(NPT_OutputStreamReference& stream) : m_Stream(stream) {} | |
77 NPT_Result operator()(NPT_HttpHeader*& header) const { | |
78 m_Stream->WriteString(header->GetName()); | |
79 m_Stream->Write(": ", 2); | |
80 m_Stream->WriteString(header->GetValue()); | |
81 m_Stream->Write("\r\n", 2, NULL); | |
82 return NPT_SUCCESS; | |
83 } | |
84 | |
85 private: | |
86 // members | |
87 NPT_OutputStreamReference& m_Stream; | |
88 }; | |
89 | |
90 /*---------------------------------------------------------------------- | |
91 | NPT_HttpHeaderLogger | |
92 +---------------------------------------------------------------------*/ | |
93 class NPT_HttpHeaderLogger | |
94 { | |
95 public: | |
96 // methods | |
97 NPT_HttpHeaderLogger(NPT_LoggerReference& logger, int level) : | |
98 m_Logger(logger), m_Level(level) {} | |
99 NPT_Result operator()(NPT_HttpHeader*& header) const { | |
100 NPT_COMPILER_UNUSED(header); | |
101 | |
102 NPT_LOG_L2(m_Logger, m_Level, "%s: %s", | |
103 (const char*)header->GetName(), | |
104 (const char*)header->GetValue()); | |
105 return NPT_SUCCESS; | |
106 } | |
107 | |
108 NPT_LoggerReference& m_Logger; | |
109 int m_Level; | |
110 }; | |
111 | |
112 | |
113 /*---------------------------------------------------------------------- | |
114 | PLT_HttpHelper::GetContentType | |
115 +---------------------------------------------------------------------*/ | |
116 NPT_Result | |
117 PLT_HttpHelper::GetContentType(NPT_HttpMessage& message, NPT_String& type) | |
118 { | |
119 type = ""; | |
120 | |
121 const NPT_String* val = | |
122 message.GetHeaders().GetHeaderValue(NPT_HTTP_HEADER_CONTENT_TYPE); | |
123 NPT_CHECK_POINTER(val); | |
124 | |
125 type = *val; | |
126 return NPT_SUCCESS; | |
127 } | |
128 | |
129 /*---------------------------------------------------------------------- | |
130 | PLT_HttpHelper::SetContentType | |
131 +---------------------------------------------------------------------*/ | |
132 void | |
133 PLT_HttpHelper::SetContentType(NPT_HttpMessage& message, const char* type) | |
134 { | |
135 message.GetHeaders().SetHeader(NPT_HTTP_HEADER_CONTENT_TYPE, type); | |
136 } | |
137 | |
138 /*---------------------------------------------------------------------- | |
139 | PLT_HttpHelper::GetContentLength | |
140 +---------------------------------------------------------------------*/ | |
141 NPT_Result | |
142 PLT_HttpHelper::GetContentLength(NPT_HttpMessage& message, NPT_LargeSize& len) | |
143 { | |
144 len = 0; | |
145 | |
146 const NPT_String* val = | |
147 message.GetHeaders().GetHeaderValue(NPT_HTTP_HEADER_CONTENT_LENGTH); | |
148 NPT_CHECK_POINTER(val); | |
149 | |
150 return val->ToInteger(len); | |
151 } | |
152 | |
153 /*---------------------------------------------------------------------- | |
154 | PLT_HttpHelper::SetContentLength | |
155 +---------------------------------------------------------------------*/ | |
156 void | |
157 PLT_HttpHelper::SetContentLength(NPT_HttpMessage& message, NPT_LargeSize len) | |
158 { | |
159 message.GetHeaders().SetHeader(NPT_HTTP_HEADER_CONTENT_LENGTH, NPT_String::FromIntegerU(len)); | |
160 } | |
161 | |
162 /*---------------------------------------------------------------------- | |
163 | PLT_HttpHelper::SetBody | |
164 +---------------------------------------------------------------------*/ | |
165 NPT_Result | |
166 PLT_HttpHelper::SetBody(NPT_HttpMessage& message, NPT_String& body) | |
167 { | |
168 return SetBody(message, (const char*)body, body.GetLength()); | |
169 } | |
170 | |
171 /*---------------------------------------------------------------------- | |
172 | NPT_HttpMessage::SetBody | |
173 +---------------------------------------------------------------------*/ | |
174 NPT_Result | |
175 PLT_HttpHelper::SetBody(NPT_HttpMessage& message, const char* body, NPT_Size len) | |
176 { | |
177 if (len == 0) { | |
178 return NPT_SUCCESS; | |
179 } | |
180 | |
181 // dump the body in a memory stream | |
182 NPT_MemoryStreamReference stream(new NPT_MemoryStream); | |
183 stream->Write(body, len); | |
184 | |
185 // set content length | |
186 PLT_HttpHelper::SetContentLength(message, len); | |
187 | |
188 NPT_InputStreamReference input = stream; | |
189 return SetBody(message, input, len); | |
190 } | |
191 | |
192 /*---------------------------------------------------------------------- | |
193 | NPT_HttpMessage::SetBody | |
194 +---------------------------------------------------------------------*/ | |
195 NPT_Result | |
196 PLT_HttpHelper::SetBody(NPT_HttpMessage& message, NPT_InputStreamReference& stream, NPT_LargeSize len) | |
197 { | |
198 if (len == 0) { | |
199 NPT_CHECK_SEVERE(stream->GetAvailable(len)); | |
200 } | |
201 | |
202 // get the entity | |
203 NPT_HttpEntity* entity = message.GetEntity(); | |
204 if (entity == NULL) { | |
205 // no entity yet, create one | |
206 message.SetEntity(entity = new NPT_HttpEntity()); | |
207 } | |
208 | |
209 // set the entity body | |
210 entity->SetInputStream(stream); | |
211 entity->SetContentLength(len); | |
212 return NPT_SUCCESS; | |
213 } | |
214 | |
215 /*---------------------------------------------------------------------- | |
216 | PLT_HttpHelper::GetBody | |
217 +---------------------------------------------------------------------*/ | |
218 NPT_Result | |
219 PLT_HttpHelper::GetBody(NPT_HttpMessage& message, NPT_String& body) | |
220 { | |
221 NPT_Result res; | |
222 NPT_InputStreamReference stream; | |
223 | |
224 // get stream | |
225 NPT_HttpEntity* entity = message.GetEntity(); | |
226 if (!entity || NPT_FAILED(entity->GetInputStream(stream))) { | |
227 return NPT_FAILURE; | |
228 } | |
229 | |
230 // extract body | |
231 NPT_StringOutputStream* output_stream = new NPT_StringOutputStream(&body); | |
232 res = NPT_StreamToStreamCopy(*stream, *output_stream, 0, entity->GetContentLength()); | |
233 delete output_stream; | |
234 return res; | |
235 } | |
236 | |
237 /*---------------------------------------------------------------------- | |
238 | PLT_HttpHelper::ParseBody | |
239 +---------------------------------------------------------------------*/ | |
240 NPT_Result | |
241 PLT_HttpHelper::ParseBody(NPT_HttpMessage& message, NPT_XmlElementNode*& tree) | |
242 { | |
243 // reset tree | |
244 tree = NULL; | |
245 | |
246 // read body | |
247 NPT_String body; | |
248 NPT_CHECK_WARNING(GetBody(message, body)); | |
249 | |
250 // parse body | |
251 NPT_XmlParser parser; | |
252 NPT_XmlNode* node; | |
253 NPT_CHECK_WARNING(parser.Parse(body, node)); | |
254 | |
255 tree = node->AsElementNode(); | |
256 if (!tree) { | |
257 delete node; | |
258 return NPT_FAILURE; | |
259 } | |
260 | |
261 return NPT_SUCCESS; | |
262 } | |
263 | |
264 /*---------------------------------------------------------------------- | |
265 | PLT_HttpHelper::IsConnectionKeepAlive | |
266 +---------------------------------------------------------------------*/ | |
267 bool | |
268 PLT_HttpHelper::IsConnectionKeepAlive(NPT_HttpMessage& message) | |
269 { | |
270 const NPT_String* connection = | |
271 message.GetHeaders().GetHeaderValue(NPT_HTTP_HEADER_CONNECTION); | |
272 | |
273 // if we have the keep-alive header then no matter what protocol version, we want keep-alive | |
274 // if we are in HTTP 1.1 and we don't have the keep-alive header, make sure we also don't have the Connection: close header. | |
275 NPT_String protocol = message.GetProtocol(); | |
276 if ((!protocol.Compare(NPT_HTTP_PROTOCOL_1_1, true) && (!connection || connection->Compare("close", true))) || | |
277 (connection && !connection->Compare("keep-alive", true))) { | |
278 return true; | |
279 } | |
280 | |
281 return false; | |
282 } | |
283 | |
284 /*---------------------------------------------------------------------- | |
285 | PLT_HttpHelper::IsBodyStreamSeekable | |
286 +---------------------------------------------------------------------*/ | |
287 bool | |
288 PLT_HttpHelper::IsBodyStreamSeekable(NPT_HttpMessage& message) | |
289 { | |
290 NPT_HttpEntity* entity = message.GetEntity(); | |
291 NPT_InputStreamReference stream; | |
292 if (!entity || NPT_FAILED(entity->GetInputStream(stream))) return true; | |
293 | |
294 // try to get current position and seek there | |
295 NPT_Position position; | |
296 if (NPT_FAILED(stream->Tell(position)) || | |
297 NPT_FAILED(stream->Seek(position))) { | |
298 return false; | |
299 } | |
300 | |
301 return true; | |
302 } | |
303 | |
304 /*---------------------------------------------------------------------- | |
305 | PLT_HttpHelper::GetHost | |
306 +---------------------------------------------------------------------*/ | |
307 NPT_Result | |
308 PLT_HttpHelper::GetHost(NPT_HttpRequest& request, NPT_String& value) | |
309 { | |
310 value = ""; | |
311 | |
312 const NPT_String* val = | |
313 request.GetHeaders().GetHeaderValue(NPT_HTTP_HEADER_HOST); | |
314 NPT_CHECK_POINTER(val); | |
315 | |
316 value = *val; | |
317 return NPT_SUCCESS; | |
318 } | |
319 | |
320 /*---------------------------------------------------------------------- | |
321 | PLT_HttpHelper::SetHost | |
322 +---------------------------------------------------------------------*/ | |
323 void | |
324 PLT_HttpHelper::SetHost(NPT_HttpRequest& request, const char* host) | |
325 { | |
326 request.GetHeaders().SetHeader(NPT_HTTP_HEADER_HOST, host); | |
327 } | |
328 | |
329 /*---------------------------------------------------------------------- | |
330 | PLT_HttpHelper::GetRange | |
331 +---------------------------------------------------------------------*/ | |
332 NPT_Result | |
333 PLT_HttpHelper::GetRange(NPT_HttpRequest& request, | |
334 NPT_Position& start, | |
335 NPT_Position& end) | |
336 { | |
337 start = (NPT_Position)-1; | |
338 end = (NPT_Position)-1; | |
339 | |
340 const NPT_String* range = | |
341 request.GetHeaders().GetHeaderValue(NPT_HTTP_HEADER_RANGE); | |
342 NPT_CHECK_POINTER(range); | |
343 | |
344 char s[32], e[32]; | |
345 s[0] = '\0'; | |
346 e[0] = '\0'; | |
347 int ret = sscanf(*range, "bytes=%[^-]-%s", s, e); | |
348 if (ret < 1) { | |
349 return NPT_FAILURE; | |
350 } | |
351 if (s[0] != '\0') { | |
352 NPT_ParseInteger64U(s, start); | |
353 } | |
354 if (e[0] != '\0') { | |
355 NPT_ParseInteger64U(e, end); | |
356 } | |
357 | |
358 return NPT_SUCCESS; | |
359 } | |
360 | |
361 /*---------------------------------------------------------------------- | |
362 | PLT_HttpHelper::SetRange | |
363 +---------------------------------------------------------------------*/ | |
364 void | |
365 PLT_HttpHelper::SetRange(NPT_HttpRequest& request, NPT_Position start, NPT_Position end) | |
366 { | |
367 NPT_String range = "bytes="; | |
368 if (start != (NPT_Position)-1) { | |
369 range += NPT_String::FromIntegerU(start); | |
370 } | |
371 range += '-'; | |
372 if (end != (NPT_Position)-1) { | |
373 range += NPT_String::FromIntegerU(end); | |
374 } | |
375 request.GetHeaders().SetHeader(NPT_HTTP_HEADER_RANGE, range); | |
376 } | |
377 | |
378 /*---------------------------------------------------------------------- | |
379 | PLT_HttpHelper::ToLog | |
380 +---------------------------------------------------------------------*/ | |
381 NPT_Result | |
382 PLT_HttpHelper::ToLog(NPT_LoggerReference logger, int level, NPT_HttpRequest* request) | |
383 { | |
384 NPT_COMPILER_UNUSED(logger); | |
385 NPT_COMPILER_UNUSED(level); | |
386 | |
387 if (!request) { | |
388 NPT_LOG_L(logger, level, "NULL HTTP Request!"); | |
389 return NPT_FAILURE; | |
390 } | |
391 | |
392 NPT_StringOutputStreamReference stream(new NPT_StringOutputStream); | |
393 NPT_OutputStreamReference output = stream; | |
394 request->GetHeaders().GetHeaders().Apply(NPT_HttpHeaderPrinter(output)); | |
395 | |
396 NPT_LOG_L4(logger, level, "\n%s %s %s\n%s", | |
397 (const char*)request->GetMethod(), | |
398 (const char*)request->GetUrl().ToRequestString(true), | |
399 (const char*)request->GetProtocol(), | |
400 (const char*)stream->GetString()); | |
401 return NPT_SUCCESS; | |
402 } | |
403 | |
404 /*---------------------------------------------------------------------- | |
405 | PLT_HttpHelper::GetContentRange | |
406 +---------------------------------------------------------------------*/ | |
407 NPT_Result | |
408 PLT_HttpHelper::GetContentRange(NPT_HttpResponse& response, | |
409 NPT_Position& start, | |
410 NPT_Position& end, | |
411 NPT_LargeSize& length) | |
412 { | |
413 const NPT_String* range = | |
414 response.GetHeaders().GetHeaderValue(NPT_HTTP_HEADER_CONTENT_RANGE); | |
415 NPT_CHECK_POINTER(range); | |
416 | |
417 start = (NPT_Position)-1; | |
418 end = (NPT_Position)-1; | |
419 length = (NPT_LargeSize)-1; | |
420 | |
421 char s[32], e[32], l[32]; | |
422 s[0] = '\0'; | |
423 e[0] = '\0'; | |
424 l[0] = '\0'; | |
425 int ret = sscanf(*range, "bytes %[^-]-%s[^/]/%s", s, e, l); | |
426 if (ret < 3) { | |
427 return NPT_FAILURE; | |
428 } | |
429 if (s[0] != '\0') { | |
430 NPT_ParseInteger64U(s, start); | |
431 } | |
432 if (e[0] != '\0') { | |
433 NPT_ParseInteger64U(e, end); | |
434 } | |
435 if (l[0] != '\0') { | |
436 NPT_ParseInteger64U(l, length); | |
437 } | |
438 return NPT_SUCCESS; | |
439 } | |
440 | |
441 /*---------------------------------------------------------------------- | |
442 | PLT_HttpHelper::SetContentRange | |
443 +---------------------------------------------------------------------*/ | |
444 NPT_Result | |
445 PLT_HttpHelper::SetContentRange(NPT_HttpResponse& response, | |
446 NPT_Position start, | |
447 NPT_Position end, | |
448 NPT_LargeSize length) | |
449 { | |
450 if (start == (NPT_Position)-1 || end == (NPT_Position)-1 || length == (NPT_Size)-1) { | |
451 NPT_LOG_WARNING_3("Content Range is exactly -1? (start=%d, end=%d, length=%d)", start, end, length); | |
452 } | |
453 | |
454 NPT_String range = "bytes "; | |
455 range += NPT_String::FromIntegerU(start); | |
456 range += '-'; | |
457 range += NPT_String::FromIntegerU(end); | |
458 range += '/'; | |
459 range += NPT_String::FromIntegerU(length); | |
460 response.GetHeaders().SetHeader(NPT_HTTP_HEADER_CONTENT_RANGE, range); | |
461 return NPT_SUCCESS; | |
462 } | |
463 | |
464 /*---------------------------------------------------------------------- | |
465 | NPT_HttpResponse::ToLog | |
466 +---------------------------------------------------------------------*/ | |
467 NPT_Result | |
468 PLT_HttpHelper::ToLog(NPT_LoggerReference logger, int level, NPT_HttpResponse* response) | |
469 { | |
470 NPT_COMPILER_UNUSED(logger); | |
471 NPT_COMPILER_UNUSED(level); | |
472 | |
473 if (!response) { | |
474 NPT_LOG_L(logger, level, "NULL HTTP Response!"); | |
475 return NPT_FAILURE; | |
476 } | |
477 | |
478 NPT_StringOutputStreamReference stream(new NPT_StringOutputStream); | |
479 NPT_OutputStreamReference output = stream; | |
480 response->GetHeaders().GetHeaders().Apply(NPT_HttpHeaderPrinter(output)); | |
481 | |
482 NPT_LOG_L4(logger, level, "\n%s %d %s\n%s", | |
483 (const char*)response->GetProtocol(), | |
484 response->GetStatusCode(), | |
485 (const char*)response->GetReasonPhrase(), | |
486 (const char*)stream->GetString()); | |
487 return NPT_SUCCESS; | |
488 } | |
489 | |
490 /*---------------------------------------------------------------------- | |
491 | PLT_HttpClient::Connect | |
492 +---------------------------------------------------------------------*/ | |
493 NPT_Result | |
494 PLT_HttpClient::Connect(NPT_Socket* connection, NPT_HttpRequest& request, NPT_Timeout timeout) | |
495 { | |
496 // get the address of the server | |
497 NPT_IpAddress server_address; | |
498 NPT_CHECK_SEVERE(server_address.ResolveName(request.GetUrl().GetHost(), timeout)); | |
499 NPT_SocketAddress address(server_address, request.GetUrl().GetPort()); | |
500 | |
501 // connect to the server | |
502 NPT_LOG_FINER_2("Connecting to %s:%d\n", (const char*)request.GetUrl().GetHost(), request.GetUrl().GetPort()); | |
503 NPT_CHECK_SEVERE(connection->Connect(address, timeout)); | |
504 | |
505 return NPT_SUCCESS; | |
506 } | |
507 | |
508 /*---------------------------------------------------------------------- | |
509 | PLT_HttpClient::SendRequest | |
510 +---------------------------------------------------------------------*/ | |
511 NPT_Result | |
512 PLT_HttpClient::SendRequest(NPT_OutputStreamReference& output_stream, | |
513 NPT_HttpRequest& request, | |
514 NPT_Timeout timeout) | |
515 { | |
516 NPT_COMPILER_UNUSED(timeout); | |
517 | |
518 // connect to the server | |
519 NPT_LOG_FINE("Sending:"); | |
520 PLT_LOG_HTTP_MESSAGE(NPT_LOG_LEVEL_FINE, &request); | |
521 | |
522 // add any headers that may be missing | |
523 NPT_HttpHeaders& headers = request.GetHeaders(); | |
524 headers.SetHeader(NPT_HTTP_HEADER_CONNECTION, "close", false); // set but don't replace | |
525 headers.SetHeader(NPT_HTTP_HEADER_USER_AGENT, | |
526 NPT_HttpClient::m_UserAgentHeader, false); // set but don't replace | |
527 | |
528 // set host only if not already set | |
529 if (!headers.GetHeader(NPT_HTTP_HEADER_HOST)) { | |
530 NPT_String host = request.GetUrl().GetHost(); | |
531 if (request.GetUrl().GetPort() != NPT_HTTP_DEFAULT_PORT) { | |
532 host += ":"; | |
533 host += NPT_String::FromInteger(request.GetUrl().GetPort()); | |
534 } | |
535 headers.SetHeader(NPT_HTTP_HEADER_HOST, host); | |
536 } | |
537 | |
538 // get the request entity to set additional headers | |
539 NPT_InputStreamReference body_stream; | |
540 NPT_HttpEntity* entity = request.GetEntity(); | |
541 if (entity && NPT_SUCCEEDED(entity->GetInputStream(body_stream))) { | |
542 // content length | |
543 headers.SetHeader(NPT_HTTP_HEADER_CONTENT_LENGTH, | |
544 NPT_String::FromIntegerU(entity->GetContentLength())); | |
545 | |
546 // content type | |
547 NPT_String content_type = entity->GetContentType(); | |
548 if (!content_type.IsEmpty()) { | |
549 headers.SetHeader(NPT_HTTP_HEADER_CONTENT_TYPE, content_type); | |
550 } | |
551 | |
552 // content encoding | |
553 NPT_String content_encoding = entity->GetContentEncoding(); | |
554 if (!content_encoding.IsEmpty()) { | |
555 headers.SetHeader(NPT_HTTP_HEADER_CONTENT_ENCODING, content_encoding); | |
556 } | |
557 } else { | |
558 // force content length to 0 is there is no message body | |
559 headers.SetHeader(NPT_HTTP_HEADER_CONTENT_LENGTH, "0"); | |
560 } | |
561 | |
562 // create a memory stream to buffer the headers | |
563 NPT_MemoryStream header_stream; | |
564 | |
565 // emit the request headers into the header buffer | |
566 request.Emit(header_stream); | |
567 | |
568 // send the headers | |
569 NPT_CHECK_SEVERE(output_stream->WriteFully(header_stream.GetData(), header_stream.GetDataSize())); | |
570 | |
571 // send request body | |
572 if (!body_stream.IsNull() && entity->GetContentLength()) { | |
573 NPT_CHECK_SEVERE(NPT_StreamToStreamCopy(*body_stream.AsPointer(), *output_stream.AsPointer())); | |
574 } | |
575 | |
576 // flush the output stream so that everything is sent to the server | |
577 output_stream->Flush(); | |
578 | |
579 return NPT_SUCCESS; | |
580 } | |
581 | |
582 /*---------------------------------------------------------------------- | |
583 | PLT_HttpClient::WaitForResponse | |
584 +---------------------------------------------------------------------*/ | |
585 NPT_Result | |
586 PLT_HttpClient::WaitForResponse(NPT_InputStreamReference& input_stream, | |
587 NPT_HttpRequest& request, | |
588 const NPT_HttpRequestContext& context, | |
589 NPT_HttpResponse*& response) | |
590 { | |
591 NPT_COMPILER_UNUSED(context); | |
592 | |
593 // create a buffered stream for this connection stream | |
594 NPT_BufferedInputStreamReference buffered_input_stream(new NPT_BufferedInputStream(input_stream)); | |
595 | |
596 // parse the response | |
597 NPT_CHECK(NPT_HttpResponse::Parse(*buffered_input_stream, response)); | |
598 | |
599 // unbuffer the stream | |
600 buffered_input_stream->SetBufferSize(0); | |
601 | |
602 // create an entity if one is expected in the response | |
603 if (request.GetMethod() == NPT_HTTP_METHOD_GET || request.GetMethod() == NPT_HTTP_METHOD_POST) { | |
604 NPT_HttpEntity* response_entity = new NPT_HttpEntity(response->GetHeaders()); | |
605 // Transfer-Encoding: chunked ? | |
606 if (response_entity->GetTransferEncoding() == "chunked") { | |
607 NPT_InputStreamReference body_stream(new NPT_HttpChunkedDecoderInputStream(buffered_input_stream)); | |
608 response_entity->SetInputStream((NPT_InputStreamReference)body_stream); | |
609 } else { | |
610 response_entity->SetInputStream((NPT_InputStreamReference)buffered_input_stream); | |
611 } | |
612 response->SetEntity(response_entity); | |
613 } | |
614 | |
615 return NPT_SUCCESS; | |
616 } |