1 /*
2  * Archttp - A highly performant web framework written in D.
3  *
4  * Copyright (C) 2021-2022 Kerisy.com
5  *
6  * Website: https://www.kerisy.com
7  *
8  * Licensed under the Apache-2.0 License.
9  *
10  */
11 
12 module archttp.HttpResponse;
13 
14 import archttp.HttpStatusCode;
15 import archttp.HttpContext;
16 
17 import gear.util.DateTime;
18 
19 import std.format;
20 import std.array;
21 import std.conv : to;
22 import std.json;
23 
24 class HttpResponse
25 {
26     alias string[string]   headerList;
27 
28     ushort       _status = HttpStatusCode.OK;
29     headerList   _headers;
30     string       _body;
31     string       _buffer;
32     HttpContext  _httpContext;
33 
34 public:
35     /*
36      * Construct an empty response.
37      */
38     this(HttpContext ctx)
39     {
40         _httpContext = ctx;
41     }
42 
43     /*
44      * Sets a header field.
45      *
46      * Setting the same header twice will overwrite the previous, and header keys are case
47      * insensitive. When sent to the client the header key will be as written here.
48      *
49      * @param header the header key
50      * @param value the header value
51      */
52     HttpResponse header(string header, string value)
53     {
54         _headers[header] = value;
55         
56         return this;
57     }
58 
59     /*
60      * Set the HTTP status of the response.
61      *
62      * @param status_code the status code
63      */
64     HttpResponse status(HttpStatusCode status_code)
65     {
66         _status = status_code;
67 
68         return this;
69     }
70 
71     /*
72      * Set the entire body of the response.
73      *
74      * Sets the body of the response, overwriting any previous data stored in the body.
75      *
76      * @param body the response body
77      */
78     HttpResponse body(string body)
79     {
80         _body = body;
81         
82         header("Content-Type", "text/plain");
83 
84         return this;
85     }
86 
87     /*
88      * Set the entire body of the response.
89      *
90      * Sets the body of the response, overwriting any previous data stored in the body.
91      *
92      * @param json the response body
93      */
94     HttpResponse json(JSONValue json)
95     {
96         _body = json.toString();
97 
98         header("Content-Type", "application/json");
99 
100         return this;
101     }
102 
103     /*
104      * Get the status of the response.
105      *
106      * @return the status of the response
107      */
108     ushort status()
109     {
110         return _status;
111     }
112 
113     //  -----  serializer  -----
114 
115     /*
116      * Generate an HTTP response from this object.
117      *
118      * Uses the configured parameters to generate a full HTTP response and returns it as a
119      * string.
120      *
121      * @return the HTTP response
122      */
123     string ToBuffer()
124     {
125         header("Content-Length", _body.length.to!string);
126         header("Date", DateTime.GetTimeAsGMT());
127 
128         auto text = appender!string;
129         text ~= format!"HTTP/1.1 %d %s\r\n"(_status, getHttpStatusMessage(_status));
130         foreach (name, value; _headers) {
131             text ~= format!"%s: %s\r\n"(name, value);
132         }
133         text ~= "\r\n";
134 
135         text ~= _body;
136         
137         return text[];
138     }
139 }