فهرست منبع

WebServer: Add Content-Length header to HTTP responses

This makes the browser know how much data it should expect.
Maciej 3 سال پیش
والد
کامیت
c1ca009939
2فایلهای تغییر یافته به همراه29 افزوده شده و 23 حذف شده
  1. 23 22
      Userland/Services/WebServer/Client.cpp
  2. 6 1
      Userland/Services/WebServer/Client.h

+ 23 - 22
Userland/Services/WebServer/Client.cpp

@@ -164,11 +164,11 @@ ErrorOr<bool> Client::handle_request(ReadonlyBytes raw_request)
 
     Core::InputFileStream stream { file };
 
-    TRY(send_response(stream, request, Core::guess_mime_type_based_on_filename(real_path)));
+    TRY(send_response(stream, request, { .type = Core::guess_mime_type_based_on_filename(real_path), .length = TRY(Core::File::size(real_path)) }));
     return true;
 }
 
-ErrorOr<void> Client::send_response(InputStream& response, HTTP::HttpRequest const& request, String const& content_type)
+ErrorOr<void> Client::send_response(InputStream& response, HTTP::HttpRequest const& request, ContentInfo content_info)
 {
     StringBuilder builder;
     builder.append("HTTP/1.0 200 OK\r\n");
@@ -176,9 +176,8 @@ ErrorOr<void> Client::send_response(InputStream& response, HTTP::HttpRequest con
     builder.append("X-Frame-Options: SAMEORIGIN\r\n");
     builder.append("X-Content-Type-Options: nosniff\r\n");
     builder.append("Pragma: no-cache\r\n");
-    builder.append("Content-Type: ");
-    builder.append(content_type);
-    builder.append("\r\n");
+    builder.appendff("Content-Type: {}\r\n", content_info.type);
+    builder.appendff("Content-Length: {}\r\n", content_info.length);
     builder.append("\r\n");
 
     auto builder_contents = builder.to_byte_buffer();
@@ -326,31 +325,33 @@ ErrorOr<void> Client::handle_directory_listing(String const& requested_path, Str
 
     auto response = builder.to_string();
     InputMemoryStream stream { response.bytes() };
-    return send_response(stream, request, "text/html");
+    return send_response(stream, request, { .type = "text/html", .length = response.length() });
 }
 
 ErrorOr<void> Client::send_error_response(unsigned code, HTTP::HttpRequest const& request, Vector<String> const& headers)
 {
     auto reason_phrase = HTTP::HttpResponse::reason_phrase_for_code(code);
-    StringBuilder builder;
-    builder.appendff("HTTP/1.0 {} ", code);
-    builder.append(reason_phrase);
-    builder.append("\r\n");
 
-    for (auto& header : headers) {
-        builder.append(header);
-        builder.append("\r\n");
-    }
-    builder.append("Content-Type: text/html; charset=UTF-8\r\n");
+    StringBuilder content_builder;
+    content_builder.append("<!DOCTYPE html><html><body><h1>");
+    content_builder.appendff("{} ", code);
+    content_builder.append(reason_phrase);
+    content_builder.append("</h1></body></html>");
 
-    builder.append("\r\n");
-    builder.append("<!DOCTYPE html><html><body><h1>");
-    builder.appendff("{} ", code);
-    builder.append(reason_phrase);
-    builder.append("</h1></body></html>");
+    StringBuilder header_builder;
+    header_builder.appendff("HTTP/1.0 {} ", code);
+    header_builder.append(reason_phrase);
+    header_builder.append("\r\n");
 
-    auto builder_contents = builder.to_byte_buffer();
-    TRY(m_socket->write(builder_contents));
+    for (auto& header : headers) {
+        header_builder.append(header);
+        header_builder.append("\r\n");
+    }
+    header_builder.append("Content-Type: text/html; charset=UTF-8\r\n");
+    header_builder.appendff("Content-Length: {}\r\n", content_builder.length());
+    header_builder.append("\r\n");
+    TRY(m_socket->write(header_builder.to_byte_buffer()));
+    TRY(m_socket->write(content_builder.to_byte_buffer()));
 
     log_response(code, request);
     return {};

+ 6 - 1
Userland/Services/WebServer/Client.h

@@ -22,8 +22,13 @@ public:
 private:
     Client(NonnullOwnPtr<Core::Stream::BufferedTCPSocket>, Core::Object* parent);
 
+    struct ContentInfo {
+        String type;
+        size_t length {};
+    };
+
     ErrorOr<bool> handle_request(ReadonlyBytes);
-    ErrorOr<void> send_response(InputStream&, HTTP::HttpRequest const&, String const& content_type);
+    ErrorOr<void> send_response(InputStream&, HTTP::HttpRequest const&, ContentInfo);
     ErrorOr<void> send_redirect(StringView redirect, HTTP::HttpRequest const&);
     ErrorOr<void> send_error_response(unsigned code, HTTP::HttpRequest const&, Vector<String> const& headers = {});
     void die();