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