/*---------------------------------------------------------------------- | PLT_HttpHelper::IsBodyStreamSeekable +---------------------------------------------------------------------*/ bool PLT_HttpHelper::IsBodyStreamSeekable(NPT_HttpMessage* message) { NPT_HttpEntity* entity = message->GetEntity(); NPT_InputStreamReference stream; if (!entity || NPT_FAILED(entity->GetInputStream(stream))) return true; // try to get current position and seek there NPT_Position position; if (NPT_FAILED(stream->Tell(position)) || NPT_FAILED(stream->Seek(position))) { return false; } return true; }
/*---------------------------------------------------------------------- | PLT_HttpHelper::GetBody +---------------------------------------------------------------------*/ NPT_Result PLT_HttpHelper::GetBody(NPT_HttpMessage& message, NPT_String& body) { NPT_Result res; NPT_InputStreamReference stream; // get stream NPT_HttpEntity* entity = message.GetEntity(); if (!entity || NPT_FAILED(entity->GetInputStream(stream))) { return NPT_FAILURE; } // extract body NPT_StringOutputStream* output_stream = new NPT_StringOutputStream(&body); res = NPT_StreamToStreamCopy(*stream, *output_stream, 0, entity->GetContentLength()); delete output_stream; return res; }
/*---------------------------------------------------------------------- | ShowResponse +---------------------------------------------------------------------*/ static void ShowResponse(NPT_HttpResponse* response) { bool check_available = true;//true; // show entity NPT_HttpEntity* entity = response->GetEntity(); if (entity == NULL) return; NPT_Console::OutputF("ENTITY: length=%lld, type=%s, encoding=%s\n", entity->GetContentLength(), entity->GetContentType().GetChars(), entity->GetContentEncoding().GetChars()); NPT_DataBuffer buffer(65536); NPT_Result result; NPT_InputStreamReference input; entity->GetInputStream(input); NPT_TimeStamp start; NPT_System::GetCurrentTimeStamp(start); float total_read = 0.0f; for (;;) { NPT_Size bytes_read = 0; NPT_LargeSize available = 0; NPT_Size to_read = 65536; if (check_available) { input->GetAvailable(available); if ((NPT_Size)available < to_read) to_read = (NPT_Size)available; if (to_read == 0) { to_read = 1; NPT_TimeStamp sleep_time(0.01f); NPT_System::Sleep(sleep_time); } } result = input->Read(buffer.UseData(), to_read, &bytes_read); if (NPT_FAILED(result)) break; total_read += bytes_read; NPT_TimeStamp now; NPT_System::GetCurrentTimeStamp(now); NPT_TimeStamp duration = now-start; NPT_Console::OutputF("%6d avail, read %6d bytes, %6.3f KB/s\n", (int)available, bytes_read, (float)((total_read/1024.0)/(double)duration)); } }
/*---------------------------------------------------------------------- | PLT_Downloader::ProcessResponse +---------------------------------------------------------------------*/ NPT_Result PLT_Downloader::ProcessResponse(NPT_Result res, const NPT_HttpRequest& request, const NPT_HttpRequestContext& context, NPT_HttpResponse* response) { NPT_COMPILER_UNUSED(request); NPT_COMPILER_UNUSED(context); if (NPT_FAILED(res)) { NPT_LOG_WARNING_2("Downloader error %d for %s", res, m_URL.ToString().GetChars()); m_State = PLT_DOWNLOADER_ERROR; return res; } m_State = PLT_DOWNLOADER_DOWNLOADING; NPT_HttpEntity* entity; NPT_InputStreamReference body; if (!response || !(entity = response->GetEntity()) || NPT_FAILED(entity->GetInputStream(body)) || body.IsNull()) { m_State = PLT_DOWNLOADER_ERROR; NPT_LOG_WARNING_2("No body %d for %s", res, m_URL.ToString().GetChars()); return NPT_FAILURE; } // Read body (no content length means until socket is closed) res = NPT_StreamToStreamCopy(*body.AsPointer(), *m_Output.AsPointer(), 0, entity->GetContentLength()); if (NPT_FAILED(res)) { NPT_LOG_WARNING_2("Downloader error %d for %s", res, m_URL.ToString().GetChars()); m_State = PLT_DOWNLOADER_ERROR; return res; } NPT_LOG_INFO_1("Finished downloading %s", m_URL.ToString().GetChars()); m_State = PLT_DOWNLOADER_SUCCESS; return NPT_SUCCESS; }
/*---------------------------------------------------------------------- | PLT_Downloader::ProcessResponse +---------------------------------------------------------------------*/ NPT_Result PLT_Downloader::ProcessResponse(NPT_Result res, NPT_HttpRequest* request, const NPT_HttpRequestContext& context, NPT_HttpResponse* response) { NPT_COMPILER_UNUSED(request); NPT_COMPILER_UNUSED(context); if (NPT_FAILED(res)) { m_State = PLT_DOWNLOADER_ERROR; return res; } m_State = PLT_DOWNLOADER_DOWNLOADING; NPT_HttpEntity* entity; NPT_InputStreamReference body; if (!response || !(entity = response->GetEntity()) || NPT_FAILED(entity->GetInputStream(body)) || body.IsNull()) { m_State = PLT_DOWNLOADER_ERROR; return NPT_FAILURE; } // Read body (no content length means until socket is closed) res = NPT_StreamToStreamCopy(*body.AsPointer(), *m_Output.AsPointer(), 0, entity->GetContentLength()); if (NPT_FAILED(res)) { m_State = PLT_DOWNLOADER_ERROR; return res; } m_State = PLT_DOWNLOADER_SUCCESS; return NPT_SUCCESS; }
/*---------------------------------------------------------------------- | PLT_HttpServerSocketTask::SendResponseBody +---------------------------------------------------------------------*/ NPT_Result PLT_HttpServerSocketTask::SendResponseBody(NPT_HttpResponse* response, NPT_OutputStream& output_stream) { NPT_HttpEntity* entity = response->GetEntity(); if (!entity) return NPT_SUCCESS; NPT_InputStreamReference body_stream; entity->GetInputStream(body_stream); if (body_stream.IsNull()) return NPT_SUCCESS; // check for chunked transfer encoding NPT_OutputStream* dest = &output_stream; if (entity->GetTransferEncoding() == NPT_HTTP_TRANSFER_ENCODING_CHUNKED) { dest = new NPT_HttpChunkedOutputStream(output_stream); } // send body NPT_LOG_FINE_1("sending body stream, %lld bytes", entity->GetContentLength()); NPT_LargeSize bytes_written = 0; NPT_Result result = NPT_StreamToStreamCopy(*body_stream, *dest, 0, entity->GetContentLength(), &bytes_written); /* passing 0 if content length is unknown will read until nothing is left */ if (NPT_FAILED(result)) { NPT_LOG_FINE_3("body stream only partially sent, %lld bytes (%d:%s)", bytes_written, result, NPT_ResultText(result)); } // flush to write out any buffered data left in chunked output if used dest->Flush(); // cleanup (this will send zero size chunk followed by CRLF) if (dest != &output_stream) delete dest; return result; }
/*---------------------------------------------------------------------- | PLT_HttpClient::SendRequest +---------------------------------------------------------------------*/ NPT_Result PLT_HttpClient::SendRequest(NPT_OutputStreamReference& output_stream, NPT_HttpRequest& request, NPT_Timeout timeout) { NPT_COMPILER_UNUSED(timeout); // connect to the server NPT_LOG_FINE("Sending:"); PLT_LOG_HTTP_MESSAGE(NPT_LOG_LEVEL_FINE, &request); // add any headers that may be missing NPT_HttpHeaders& headers = request.GetHeaders(); //headers.SetHeader(NPT_HTTP_HEADER_CONNECTION, "close"); if (!headers.GetHeader(NPT_HTTP_HEADER_USER_AGENT)) { headers.SetHeader(NPT_HTTP_HEADER_USER_AGENT, "Platinum/" PLT_PLATINUM_VERSION_STRING); } // set host only if not already set if (!headers.GetHeader(NPT_HTTP_HEADER_HOST)) { NPT_String host = request.GetUrl().GetHost(); if (request.GetUrl().GetPort() != NPT_HTTP_DEFAULT_PORT) { host += ":"; host += NPT_String::FromInteger(request.GetUrl().GetPort()); } headers.SetHeader(NPT_HTTP_HEADER_HOST, host); } // get the request entity to set additional headers NPT_InputStreamReference body_stream; NPT_HttpEntity* entity = request.GetEntity(); if (entity && NPT_SUCCEEDED(entity->GetInputStream(body_stream))) { // content length headers.SetHeader(NPT_HTTP_HEADER_CONTENT_LENGTH, NPT_String::FromInteger(entity->GetContentLength())); // content type NPT_String content_type = entity->GetContentType(); if (!content_type.IsEmpty()) { headers.SetHeader(NPT_HTTP_HEADER_CONTENT_TYPE, content_type); } // content encoding NPT_String content_encoding = entity->GetContentEncoding(); if (!content_encoding.IsEmpty()) { headers.SetHeader(NPT_HTTP_HEADER_CONTENT_ENCODING, content_encoding); } } else { // force content length to 0 is there is no message body headers.SetHeader(NPT_HTTP_HEADER_CONTENT_LENGTH, "0"); } // create a memory stream to buffer the headers NPT_MemoryStream header_stream; // emit the request headers into the header buffer request.Emit(header_stream); // send the headers NPT_CHECK_SEVERE(output_stream->WriteFully(header_stream.GetData(), header_stream.GetDataSize())); // send request body if (!body_stream.IsNull() && entity->GetContentLength()) { NPT_CHECK_SEVERE(NPT_StreamToStreamCopy(*body_stream.AsPointer(), *output_stream.AsPointer())); } // flush the output stream so that everything is sent to the server output_stream->Flush(); return NPT_SUCCESS; }
/*---------------------------------------------------------------------- | ShowResponse +---------------------------------------------------------------------*/ static void ShowResponse(NPT_HttpResponse* response, ShowMode mode) { // show response info NPT_Debug("RESPONSE: protocol=%s, code=%d, reason=%s\n", response->GetProtocol().GetChars(), response->GetStatusCode(), response->GetReasonPhrase().GetChars()); // show headers NPT_HttpHeaders& headers = response->GetHeaders(); NPT_List<NPT_HttpHeader*>::Iterator header = headers.GetHeaders().GetFirstItem(); while (header) { NPT_Debug("%s: %s\n", (const char*)(*header)->GetName(), (const char*)(*header)->GetValue()); ++header; } // show entity NPT_HttpEntity* entity = response->GetEntity(); if (entity != NULL) { NPT_Debug("ENTITY: length=%lld, type=%s, encoding=%s\n", entity->GetContentLength(), entity->GetContentType().GetChars(), entity->GetContentEncoding().GetChars()); switch (mode) { case SHOW_MODE_LOAD: { NPT_DataBuffer body; NPT_Result result =entity->Load(body); if (NPT_FAILED(result)) { NPT_Debug("ERROR: failed to load entity (%d)\n", result); } else { NPT_Debug("BODY: loaded %d bytes\n", (int)body.GetDataSize()); // dump the body NPT_OutputStreamReference output; NPT_File standard_out(NPT_FILE_STANDARD_OUTPUT); standard_out.Open(NPT_FILE_OPEN_MODE_WRITE); standard_out.GetOutputStream(output); NPT_Debug("%s", (char *)body.GetData()); // ÔÝʱ²»Ö§³Ö // output->Write(body.GetData(), body.GetDataSize()); } break; } case SHOW_MODE_STREAM_BLOCKING: { NPT_DataBuffer buffer(4096); NPT_Result result; NPT_InputStreamReference input; entity->GetInputStream(input); do { NPT_Size bytes_read = 0; result = input->Read(buffer.UseData(), 4096, &bytes_read); NPT_Debug("read %d bytes\n", bytes_read); } while (NPT_SUCCEEDED(result)); break; } } } }
/*---------------------------------------------------------------------- | PLT_HttpServerSocketTask::SendResponseHeaders +---------------------------------------------------------------------*/ NPT_Result PLT_HttpServerSocketTask::SendResponseHeaders(NPT_HttpResponse* response, NPT_OutputStream& output_stream, bool& keep_alive) { // add any headers that may be missing NPT_HttpHeaders& headers = response->GetHeaders(); // get the request entity to set additional headers NPT_InputStreamReference body_stream; NPT_HttpEntity* entity = response->GetEntity(); if (entity && NPT_SUCCEEDED(entity->GetInputStream(body_stream))) { // set the content length if known if (entity->ContentLengthIsKnown()) { headers.SetHeader(NPT_HTTP_HEADER_CONTENT_LENGTH, NPT_String::FromIntegerU(entity->GetContentLength())); } // content type NPT_String content_type = entity->GetContentType(); if (!content_type.IsEmpty()) { headers.SetHeader(NPT_HTTP_HEADER_CONTENT_TYPE, content_type); } // content encoding NPT_String content_encoding = entity->GetContentEncoding(); if (!content_encoding.IsEmpty()) { headers.SetHeader(NPT_HTTP_HEADER_CONTENT_ENCODING, content_encoding); } // transfer encoding const NPT_String& transfer_encoding = entity->GetTransferEncoding(); if (!transfer_encoding.IsEmpty()) { headers.SetHeader(NPT_HTTP_HEADER_TRANSFER_ENCODING, transfer_encoding); } } else if (!headers.GetHeader(NPT_HTTP_HEADER_CONTENT_LENGTH)) { // force content length to 0 if there is no message body // (necessary for 1.1 or 1.0 with keep-alive connections) headers.SetHeader(NPT_HTTP_HEADER_CONTENT_LENGTH, "0"); } const NPT_String* content_length = headers.GetHeaderValue(NPT_HTTP_HEADER_CONTENT_LENGTH); const NPT_String* transfer_encoding = headers.GetHeaderValue(NPT_HTTP_HEADER_TRANSFER_ENCODING); const NPT_String* connection_header = headers.GetHeaderValue(NPT_HTTP_HEADER_CONNECTION); if (keep_alive) { if (connection_header && connection_header->Compare("close") == 0) { keep_alive = false; } else { // the request says client supports keep-alive // but override if response has content-length header or // transfer chunked encoding keep_alive = content_length || (transfer_encoding && transfer_encoding->Compare(NPT_HTTP_TRANSFER_ENCODING_CHUNKED) == 0); } } // only write keep-alive header for 1.1 if it's close NPT_String protocol = response->GetProtocol(); if (protocol.Compare(NPT_HTTP_PROTOCOL_1_0, true) == 0 || !keep_alive) { headers.SetHeader(NPT_HTTP_HEADER_CONNECTION, keep_alive?"keep-alive":"close", true); } headers.SetHeader(NPT_HTTP_HEADER_SERVER, PLT_HTTP_DEFAULT_SERVER, false); // set but don't replace PLT_LOG_HTTP_RESPONSE(NPT_LOG_LEVEL_FINE, "PLT_HttpServerSocketTask::Write", response); // create a memory stream to buffer the headers NPT_MemoryStream header_stream; response->Emit(header_stream); // send the headers NPT_CHECK_WARNING(output_stream.WriteFully(header_stream.GetData(), header_stream.GetDataSize())); return NPT_SUCCESS; }