@@ -27,6 +27,12 @@ namespace crow
2727 template <typename Adaptor, typename Handler, typename ... Middlewares>
2828 class Connection ;
2929
30+ namespace websocket
31+ {
32+ template <typename Adaptor, typename Handler>
33+ class Connection ;
34+ }
35+
3036 class Router ;
3137
3238 // / HTTP response
@@ -35,6 +41,9 @@ namespace crow
3541 template <typename Adaptor, typename Handler, typename ... Middlewares>
3642 friend class crow ::Connection;
3743
44+ template <typename Adaptor, typename Handler>
45+ friend class websocket ::Connection;
46+
3847 friend class Router ;
3948
4049 int code{200 }; // /< The Status code for the response.
@@ -328,6 +337,115 @@ namespace crow
328337 }
329338
330339 private:
340+ void write_header_into_buffer (std::vector<asio::const_buffer>& buffers, std::string& content_length_buffer, bool add_keep_alive, const std::string& server_name)
341+ {
342+ // TODO(EDev): HTTP version in status codes should be dynamic
343+ // Keep in sync with common.h/status
344+ static std::unordered_map<int , std::string> statusCodes = {
345+ {status::CONTINUE, " HTTP/1.1 100 Continue\r\n " },
346+ {status::SWITCHING_PROTOCOLS, " HTTP/1.1 101 Switching Protocols\r\n " },
347+
348+ {status::OK, " HTTP/1.1 200 OK\r\n " },
349+ {status::CREATED, " HTTP/1.1 201 Created\r\n " },
350+ {status::ACCEPTED, " HTTP/1.1 202 Accepted\r\n " },
351+ {status::NON_AUTHORITATIVE_INFORMATION, " HTTP/1.1 203 Non-Authoritative Information\r\n " },
352+ {status::NO_CONTENT, " HTTP/1.1 204 No Content\r\n " },
353+ {status::RESET_CONTENT, " HTTP/1.1 205 Reset Content\r\n " },
354+ {status::PARTIAL_CONTENT, " HTTP/1.1 206 Partial Content\r\n " },
355+
356+ {status::MULTIPLE_CHOICES, " HTTP/1.1 300 Multiple Choices\r\n " },
357+ {status::MOVED_PERMANENTLY, " HTTP/1.1 301 Moved Permanently\r\n " },
358+ {status::FOUND, " HTTP/1.1 302 Found\r\n " },
359+ {status::SEE_OTHER, " HTTP/1.1 303 See Other\r\n " },
360+ {status::NOT_MODIFIED, " HTTP/1.1 304 Not Modified\r\n " },
361+ {status::TEMPORARY_REDIRECT, " HTTP/1.1 307 Temporary Redirect\r\n " },
362+ {status::PERMANENT_REDIRECT, " HTTP/1.1 308 Permanent Redirect\r\n " },
363+
364+ {status::BAD_REQUEST, " HTTP/1.1 400 Bad Request\r\n " },
365+ {status::UNAUTHORIZED, " HTTP/1.1 401 Unauthorized\r\n " },
366+ {status::FORBIDDEN, " HTTP/1.1 403 Forbidden\r\n " },
367+ {status::NOT_FOUND, " HTTP/1.1 404 Not Found\r\n " },
368+ {status::METHOD_NOT_ALLOWED, " HTTP/1.1 405 Method Not Allowed\r\n " },
369+ {status::NOT_ACCEPTABLE, " HTTP/1.1 406 Not Acceptable\r\n " },
370+ {status::PROXY_AUTHENTICATION_REQUIRED, " HTTP/1.1 407 Proxy Authentication Required\r\n " },
371+ {status::CONFLICT, " HTTP/1.1 409 Conflict\r\n " },
372+ {status::GONE, " HTTP/1.1 410 Gone\r\n " },
373+ {status::PAYLOAD_TOO_LARGE, " HTTP/1.1 413 Payload Too Large\r\n " },
374+ {status::UNSUPPORTED_MEDIA_TYPE, " HTTP/1.1 415 Unsupported Media Type\r\n " },
375+ {status::RANGE_NOT_SATISFIABLE, " HTTP/1.1 416 Range Not Satisfiable\r\n " },
376+ {status::EXPECTATION_FAILED, " HTTP/1.1 417 Expectation Failed\r\n " },
377+ {status::PRECONDITION_REQUIRED, " HTTP/1.1 428 Precondition Required\r\n " },
378+ {status::TOO_MANY_REQUESTS, " HTTP/1.1 429 Too Many Requests\r\n " },
379+ {status::UNAVAILABLE_FOR_LEGAL_REASONS, " HTTP/1.1 451 Unavailable For Legal Reasons\r\n " },
380+
381+ {status::INTERNAL_SERVER_ERROR, " HTTP/1.1 500 Internal Server Error\r\n " },
382+ {status::NOT_IMPLEMENTED, " HTTP/1.1 501 Not Implemented\r\n " },
383+ {status::BAD_GATEWAY, " HTTP/1.1 502 Bad Gateway\r\n " },
384+ {status::SERVICE_UNAVAILABLE, " HTTP/1.1 503 Service Unavailable\r\n " },
385+ {status::GATEWAY_TIMEOUT, " HTTP/1.1 504 Gateway Timeout\r\n " },
386+ {status::VARIANT_ALSO_NEGOTIATES, " HTTP/1.1 506 Variant Also Negotiates\r\n " },
387+ };
388+
389+ static const std::string seperator = " : " ;
390+
391+ buffers.clear ();
392+ buffers.reserve (4 * (headers.size () + 5 ) + 3 );
393+
394+ if (!statusCodes.count (code))
395+ {
396+ CROW_LOG_WARNING << this << " status code "
397+ << " (" << code << " )"
398+ << " not defined, returning 500 instead" ;
399+ code = 500 ;
400+ }
401+
402+ auto & status = statusCodes.find (code)->second ;
403+ buffers.emplace_back (status.data (), status.size ());
404+
405+ if (code >= 400 && body.empty ())
406+ body = statusCodes[code].substr (9 );
407+
408+ for (auto & kv : headers)
409+ {
410+ buffers.emplace_back (kv.first .data (), kv.first .size ());
411+ buffers.emplace_back (seperator.data (), seperator.size ());
412+ buffers.emplace_back (kv.second .data (), kv.second .size ());
413+ buffers.emplace_back (crlf.data (), crlf.size ());
414+ }
415+
416+ if (!manual_length_header && !headers.count (" content-length" ))
417+ {
418+ content_length_buffer = std::to_string (body.size ());
419+ static std::string content_length_tag = " Content-Length: " ;
420+ buffers.emplace_back (content_length_tag.data (), content_length_tag.size ());
421+ buffers.emplace_back (content_length_buffer.data (), content_length_buffer.size ());
422+ buffers.emplace_back (crlf.data (), crlf.size ());
423+ }
424+ if (!headers.count (" server" ) && !server_name.empty ())
425+ {
426+ static std::string server_tag = " Server: " ;
427+ buffers.emplace_back (server_tag.data (), server_tag.size ());
428+ buffers.emplace_back (server_name.data (), server_name.size ());
429+ buffers.emplace_back (crlf.data (), crlf.size ());
430+ }
431+ /* if (!headers.count("date"))
432+ {
433+ static std::string date_tag = "Date: ";
434+ date_str_ = get_cached_date_str();
435+ buffers.emplace_back(date_tag.data(), date_tag.size());
436+ buffers.emplace_back(date_str_.data(), date_str_.size());
437+ buffers.emplace_back(crlf.data(), crlf.size());
438+ }*/
439+ if (add_keep_alive)
440+ {
441+ static std::string keep_alive_tag = " Connection: Keep-Alive" ;
442+ buffers.emplace_back (keep_alive_tag.data (), keep_alive_tag.size ());
443+ buffers.emplace_back (crlf.data (), crlf.size ());
444+ }
445+
446+ buffers.emplace_back (crlf.data (), crlf.size ());
447+ }
448+
331449 bool completed_{};
332450 std::function<void ()> complete_request_handler_;
333451 std::function<bool ()> is_alive_helper_;
0 commit comments