1 // 2 // Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 3 // 4 // Distributed under the Boost Software License, Version 1.0. (See accompanying 5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 // 7 #pragma once 8 9 #include "td/utils/logging.h" 10 #include "td/utils/Slice.h" 11 #include "td/utils/SliceBuilder.h" 12 #include "td/utils/Status.h" 13 #include "td/utils/StringBuilder.h" 14 15 namespace td { 16 17 class HttpHeaderCreator { 18 public: 19 static constexpr size_t MAX_HEADER = 4096; HttpHeaderCreator()20 HttpHeaderCreator() : sb_(MutableSlice{header_, MAX_HEADER}) { 21 } init_ok()22 void init_ok() { 23 sb_ = StringBuilder(MutableSlice{header_, MAX_HEADER}); 24 sb_ << "HTTP/1.1 200 OK\r\n"; 25 } init_get(Slice url)26 void init_get(Slice url) { 27 sb_ = StringBuilder(MutableSlice{header_, MAX_HEADER}); 28 sb_ << "GET " << url << " HTTP/1.1\r\n"; 29 } init_post(Slice url)30 void init_post(Slice url) { 31 sb_ = StringBuilder(MutableSlice{header_, MAX_HEADER}); 32 sb_ << "POST " << url << " HTTP/1.1\r\n"; 33 } init_error(int code,Slice reason)34 void init_error(int code, Slice reason) { 35 sb_ = StringBuilder(MutableSlice{header_, MAX_HEADER}); 36 sb_ << "HTTP/1.1 " << code << " " << reason << "\r\n"; 37 } init_status_line(int http_status_code)38 void init_status_line(int http_status_code) { 39 init_error(http_status_code, get_status_line(http_status_code)); 40 } add_header(Slice key,Slice value)41 void add_header(Slice key, Slice value) { 42 sb_ << key << ": " << value << "\r\n"; 43 } set_content_type(Slice type)44 void set_content_type(Slice type) { 45 add_header("Content-Type", type); 46 } set_content_size(size_t size)47 void set_content_size(size_t size) { 48 add_header("Content-Length", PSLICE() << size); 49 } set_keep_alive()50 void set_keep_alive() { 51 add_header("Connection", "keep-alive"); 52 } 53 54 Result<Slice> finish(Slice content = {}) TD_WARN_UNUSED_RESULT { 55 sb_ << "\r\n"; 56 if (!content.empty()) { 57 sb_ << content; 58 } 59 if (sb_.is_error()) { 60 return Status::Error("Too much headers"); 61 } 62 return sb_.as_cslice(); 63 } 64 65 private: get_status_line(int http_status_code)66 static CSlice get_status_line(int http_status_code) { 67 if (http_status_code == 200) { 68 return CSlice("OK"); 69 } 70 switch (http_status_code) { 71 case 201: 72 return CSlice("Created"); 73 case 202: 74 return CSlice("Accepted"); 75 case 204: 76 return CSlice("No Content"); 77 case 206: 78 return CSlice("Partial Content"); 79 case 301: 80 return CSlice("Moved Permanently"); 81 case 302: 82 return CSlice("Found"); 83 case 303: 84 return CSlice("See Other"); 85 case 304: 86 return CSlice("Not Modified"); 87 case 307: 88 return CSlice("Temporary Redirect"); 89 case 308: 90 return CSlice("Permanent Redirect"); 91 case 400: 92 return CSlice("Bad Request"); 93 case 401: 94 return CSlice("Unauthorized"); 95 case 403: 96 return CSlice("Forbidden"); 97 case 404: 98 return CSlice("Not Found"); 99 case 405: 100 return CSlice("Method Not Allowed"); 101 case 406: 102 return CSlice("Not Acceptable"); 103 case 408: 104 return CSlice("Request Timeout"); 105 case 409: 106 return CSlice("Conflict"); 107 case 410: 108 return CSlice("Gone"); 109 case 411: 110 return CSlice("Length Required"); 111 case 412: 112 return CSlice("Precondition Failed"); 113 case 413: 114 return CSlice("Request Entity Too Large"); 115 case 414: 116 return CSlice("Request-URI Too Long"); 117 case 415: 118 return CSlice("Unsupported Media Type"); 119 case 416: 120 return CSlice("Range Not Satisfiable"); 121 case 417: 122 return CSlice("Expectation Failed"); 123 case 418: 124 return CSlice("I'm a teapot"); 125 case 421: 126 return CSlice("Misdirected Request"); 127 case 426: 128 return CSlice("Upgrade Required"); 129 case 429: 130 return CSlice("Too Many Requests"); 131 case 431: 132 return CSlice("Request Header Fields Too Large"); 133 case 480: 134 return CSlice("Temporarily Unavailable"); 135 case 501: 136 return CSlice("Not Implemented"); 137 case 502: 138 return CSlice("Bad Gateway"); 139 case 503: 140 return CSlice("Service Unavailable"); 141 case 505: 142 return CSlice("HTTP Version Not Supported"); 143 default: 144 LOG_IF(ERROR, http_status_code != 500) << "Unsupported status code " << http_status_code << " returned"; 145 return CSlice("Internal Server Error"); 146 } 147 } 148 149 char header_[MAX_HEADER]; 150 StringBuilder sb_; 151 }; 152 153 } // namespace td 154