/*---------------------------------------------------------------------- | 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_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; }
/*---------------------------------------------------------------------- | PLT_HttpServer::ServeStream +---------------------------------------------------------------------*/ NPT_Result PLT_HttpServer::ServeStream(const NPT_HttpRequest& request, const NPT_HttpRequestContext& context, NPT_HttpResponse& response, NPT_InputStreamReference& body, const char* content_type) { if (body.IsNull()) return NPT_FAILURE; // set date NPT_TimeStamp now; NPT_System::GetCurrentTimeStamp(now); response.GetHeaders().SetHeader("Date", NPT_DateTime(now).ToString(NPT_DateTime::FORMAT_RFC_1123), true); // get entity NPT_HttpEntity* entity = response.GetEntity(); NPT_CHECK_POINTER_FATAL(entity); // set the content type entity->SetContentType(content_type); // check for range requests const NPT_String* range_spec = request.GetHeaders().GetHeaderValue(NPT_HTTP_HEADER_RANGE); // setup entity body NPT_CHECK(NPT_HttpFileRequestHandler::SetupResponseBody(response, body, range_spec)); // set some default headers if (response.GetEntity()->GetTransferEncoding() != NPT_HTTP_TRANSFER_ENCODING_CHUNKED) { // set but don't replace Accept-Range header only if body is seekable NPT_Position offset; if (NPT_SUCCEEDED(body->Tell(offset)) && NPT_SUCCEEDED(body->Seek(offset))) { response.GetHeaders().SetHeader(NPT_HTTP_HEADER_ACCEPT_RANGES, "bytes", false); } } // set getcontentFeatures.dlna.org const NPT_String* value = request.GetHeaders().GetHeaderValue("getcontentFeatures.dlna.org"); if (value) { PLT_HttpRequestContext tmp_context(request, context); const char* dlna = PLT_ProtocolInfo::GetDlnaExtension(entity->GetContentType(), &tmp_context); if (dlna) response.GetHeaders().SetHeader("ContentFeatures.DLNA.ORG", dlna, false); } // transferMode.dlna.org value = request.GetHeaders().GetHeaderValue("transferMode.dlna.org"); if (value) { // Interactive mode not supported? /*if (value->Compare("Interactive", true) == 0) { response.SetStatus(406, "Not Acceptable"); return NPT_SUCCESS; }*/ response.GetHeaders().SetHeader("TransferMode.DLNA.ORG", value->GetChars(), false); } else { response.GetHeaders().SetHeader("TransferMode.DLNA.ORG", "Streaming", false); } if (request.GetHeaders().GetHeaderValue("TimeSeekRange.dlna.org")) { response.SetStatus(406, "Not Acceptable"); return NPT_SUCCESS; } 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; }