Response format Response = Status-Line ; Section 6.1 (( general-header ; Section 4.5 | response-header ; Section 6.2 | entity-header ) CRLF) ; Section 7.1 CRLF [ message-body ] ; Section 7.2 Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
| 676 | // [ message-body ] ; Section 7.2 |
| 677 | // Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF |
| 678 | void MakeRawHttpResponse(butil::IOBuf* response, |
| 679 | HttpHeader* h, |
| 680 | butil::IOBuf* content) { |
| 681 | butil::IOBufBuilder os; |
| 682 | os << "HTTP/" << h->major_version() << '.' |
| 683 | << h->minor_version() << ' ' << h->status_code() |
| 684 | << ' ' << h->reason_phrase() << BRPC_CRLF; |
| 685 | bool is_invalid_content = h->status_code() < HTTP_STATUS_OK || |
| 686 | h->status_code() == HTTP_STATUS_NO_CONTENT; |
| 687 | bool is_head_req = h->method() == HTTP_METHOD_HEAD; |
| 688 | if (is_invalid_content) { |
| 689 | // https://www.rfc-editor.org/rfc/rfc7230#section-3.3.1 |
| 690 | // A server MUST NOT send a Transfer-Encoding header field in any |
| 691 | // response with a status code of 1xx (Informational) or 204 (No |
| 692 | // Content). |
| 693 | h->RemoveHeader("Transfer-Encoding"); |
| 694 | // https://www.rfc-editor.org/rfc/rfc7230#section-3.3.2 |
| 695 | // A server MUST NOT send a Content-Length header field in any response |
| 696 | // with a status code of 1xx (Informational) or 204 (No Content). |
| 697 | h->RemoveHeader("Content-Length"); |
| 698 | } else { |
| 699 | const std::string* transfer_encoding = h->GetHeader("Transfer-Encoding"); |
| 700 | // https://datatracker.ietf.org/doc/html/rfc7230#section-3.3.2 |
| 701 | // A sender MUST NOT send a Content-Length header field in any message |
| 702 | // that contains a Transfer-Encoding header field. |
| 703 | if (transfer_encoding) { |
| 704 | h->RemoveHeader("Content-Length"); |
| 705 | } |
| 706 | if (content) { |
| 707 | const std::string* content_length = h->GetHeader("Content-Length"); |
| 708 | if (is_head_req) { |
| 709 | if (!content_length && !transfer_encoding) { |
| 710 | // Prioritize "Content-Length" set by user. |
| 711 | // If "Content-Length" is not set, set it to the length of content. |
| 712 | os << "Content-Length: " << content->length() << BRPC_CRLF; |
| 713 | } |
| 714 | } else { |
| 715 | if (!transfer_encoding) { |
| 716 | if (content_length) { |
| 717 | h->RemoveHeader("Content-Length"); |
| 718 | } |
| 719 | // Never use "Content-Length" set by user. |
| 720 | // Always set Content-Length since lighttpd requires the header to be |
| 721 | // set to 0 for empty content. |
| 722 | os << "Content-Length: " << content->length() << BRPC_CRLF; |
| 723 | } |
| 724 | } |
| 725 | } |
| 726 | } |
| 727 | if (!is_invalid_content && !h->content_type().empty()) { |
| 728 | os << "Content-Type: " << h->content_type() |
| 729 | << BRPC_CRLF; |
| 730 | } |
| 731 | for (HttpHeader::HeaderIterator it = h->HeaderBegin(); |
| 732 | it != h->HeaderEnd(); ++it) { |
| 733 | os << it->first << ": " << it->second << BRPC_CRLF; |
| 734 | } |
| 735 | os << BRPC_CRLF; // CRLF before content |