NPT_Result NPT_StreamToStreamCopy(NPT_InputStream& from, NPT_OutputStream& to, NPT_Position offset /* = 0 */, NPT_Size size /* = 0, 0 means the entire stream */) { // seek into the input if required if (offset) { NPT_CHECK(from.Seek(offset)); } // allocate a buffer for the transfer NPT_Size bytes_transfered = 0; NPT_Byte* buffer = new NPT_Byte[NPT_STREAM_COPY_BUFFER_SIZE]; NPT_Result result = NPT_SUCCESS; if (buffer == NULL) return NPT_ERROR_OUT_OF_MEMORY; // copy until an error occurs or the end of stream is reached for (;;) { // read some data NPT_Size bytes_to_read = NPT_STREAM_COPY_BUFFER_SIZE; NPT_Size bytes_read = 0; if (size) { // a max size was specified if (bytes_to_read > size-bytes_transfered) { bytes_to_read = size-bytes_transfered; } } result = from.Read(buffer, bytes_to_read, &bytes_read); if (NPT_FAILED(result)) { if (result == NPT_ERROR_EOS) result = NPT_SUCCESS; break; } if (bytes_read == 0) continue; // write the data result = to.WriteFully(buffer, bytes_read); if (NPT_FAILED(result)) break; // update the counts if (size) { bytes_transfered += bytes_read; if (bytes_transfered >= size) break; } } // free the buffer and return delete[] buffer; return result; }
/*---------------------------------------------------------------------- | 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; }
NPT_Result SendResponseBody(const NPT_HttpRequestContext& /*context*/, NPT_HttpResponse& /*response*/, NPT_OutputStream& output) { output.WriteString("<html><body>\r\n"); for (unsigned int i=0; i<30; i++) { output.WriteString("Line "); output.WriteString(NPT_String::FromInteger(i).GetChars()); output.WriteString("\r\n"); output.Flush(); NPT_System::Sleep(NPT_TimeInterval(0.2f)); } output.WriteString("</body></html>\r\n"); return NPT_SUCCESS; }
/*---------------------------------------------------------------------- | 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; }
/*---------------------------------------------------------------------- | NPT_Log::FormatRecordToStream +---------------------------------------------------------------------*/ void NPT_Log::FormatRecordToStream(const NPT_LogRecord& record, NPT_OutputStream& stream, bool use_colors, NPT_Flags format_filter) { const char* level_name = GetLogLevelName(record.m_Level); NPT_String level_string; /* format and emit the record */ if (level_name[0] == '\0') { level_string = NPT_String::FromInteger(record.m_Level); level_name = level_string; } if ((format_filter & NPT_LOG_FORMAT_FILTER_NO_SOURCE) == 0) { unsigned int start = 0; /* remove source file path if requested */ if (format_filter & NPT_LOG_FORMAT_FILTER_NO_SOURCEPATH) { for (start = NPT_StringLength(record.m_SourceFile); start; --start) { if (record.m_SourceFile[start-1] == '\\' || record.m_SourceFile[start-1] == '/') { break; } } } stream.WriteString(record.m_SourceFile + start); stream.Write("(", 1, NULL); stream.WriteString(NPT_String::FromIntegerU(record.m_SourceLine)); stream.Write("): ", 3, NULL); } if ((format_filter & NPT_LOG_FORMAT_FILTER_NO_LOGGER_NAME) == 0) { stream.Write("[", 1, NULL); stream.WriteString(record.m_LoggerName); stream.Write("] ", 2, NULL); } if ((format_filter & NPT_LOG_FORMAT_FILTER_NO_TIMESTAMP) == 0) { NPT_String ts = NPT_DateTime(record.m_TimeStamp, true).ToString(NPT_DateTime::FORMAT_W3C, NPT_DateTime::FLAG_EMIT_FRACTION | NPT_DateTime::FLAG_EXTENDED_PRECISION); stream.WriteString(ts.GetChars()); stream.Write(" ", 1); } if ((format_filter & NPT_LOG_FORMAT_FILTER_NO_FUNCTION_NAME) == 0) { stream.WriteFully("[",1); if (record.m_SourceFunction) { stream.WriteString(record.m_SourceFunction); } stream.WriteFully("] ",2); } if ((format_filter & NPT_LOG_FORMAT_FILTER_NO_THREAD_ID) == 0) { stream.Write("(", 1, NULL); stream.WriteString(NPT_String::FromIntegerU(record.m_ThreadId)); stream.Write(") ", 2, NULL); } const char* ansi_color = NULL; if (use_colors) { ansi_color = GetLogLevelAnsiColor(record.m_Level); if (ansi_color) { stream.Write("\033[", 2, NULL); stream.WriteString(ansi_color); stream.Write(";1m", 3, NULL); } } stream.WriteString(level_name); if (use_colors && ansi_color) { stream.Write("\033[0m", 4, NULL); } stream.Write(": ", 2, NULL); stream.WriteString(record.m_Message); stream.Write("\r\n", 2, NULL); }