1 /*  =========================================================================
2     zhttp_response - zhttp server request.
3 Class can be reused.
4 
5     Copyright (c) the Contributors as noted in the AUTHORS file.
6 
7     This Source Code Form is subject to the terms of the Mozilla Public
8     License, v. 2.0. If a copy of the MPL was not distributed with this
9     file, You can obtain one at http://mozilla.org/MPL/2.0/.
10     =========================================================================
11 */
12 
13 /*
14 @header
15     zhttp_response - zhttp server request.
16 Class can be reused.
17 @discuss
18 @end
19 */
20 
21 #include "czmq_classes.h"
22 
23 //  Structure of our class
24 
25 struct _zhttp_response_t {
26     uint32_t status_code;
27     zhash_t  *headers;
28     char *content;
29     bool free_content;
30 };
31 
32 
33 //  --------------------------------------------------------------------------
34 //  Create a new zhttp_response
35 
36 zhttp_response_t *
zhttp_response_new(void)37 zhttp_response_new (void)
38 {
39     zhttp_response_t *self = (zhttp_response_t *) zmalloc (sizeof (zhttp_response_t));
40     assert (self);
41 
42     self->headers = zhash_new ();
43     zhash_autofree (self->headers);
44     self->status_code = 200;
45     self->content = NULL;
46     self->free_content = false;
47 
48     return self;
49 }
50 
51 
52 //  --------------------------------------------------------------------------
53 //  Destroy the zhttp_response
54 
55 void
zhttp_response_destroy(zhttp_response_t ** self_p)56 zhttp_response_destroy (zhttp_response_t **self_p)
57 {
58     assert (self_p);
59     if (*self_p) {
60         zhttp_response_t *self = *self_p;
61         zhash_destroy (&self->headers);
62 
63         if (self->free_content)
64             zstr_free (&self->content);
65 
66         self->content = NULL;
67         self->free_content = false;
68 
69         //  Free object itself
70         free (self);
71         *self_p = NULL;
72     }
73 }
74 
75 int
zhttp_response_send(zhttp_response_t * self,zsock_t * sock,void ** connection_p)76 zhttp_response_send (zhttp_response_t *self, zsock_t *sock, void **connection_p) {
77     assert (self);
78     assert (connection_p);
79     assert (*connection_p);
80 
81     int rc = zsock_bsend (sock, "p4p1p",
82             *connection_p, self->status_code, self->headers, self->free_content ? (byte)1 : (byte)0,
83             self->content);
84 
85     if (rc == -1)
86         return rc;
87 
88     *connection_p = NULL;
89     self->headers = zhash_new ();
90     zhash_autofree (self->headers);
91     self->content = NULL;
92     self->free_content = false;
93 
94     return 0;
95 }
96 
97 
98 int
zhttp_response_recv(zhttp_response_t * self,zhttp_client_t * client,void ** arg_p,void ** arg2_p)99 zhttp_response_recv (zhttp_response_t *self, zhttp_client_t *client, void** arg_p, void** arg2_p) {
100     assert (self);
101     assert (client);
102 
103     zhash_destroy (&self->headers);
104     if (self->free_content) {
105         zstr_free (&self->content);
106         self->free_content = false;
107     }
108 
109     uint32_t result;
110     int rc = zsock_brecv (client, "4pp4pp", &result, arg_p, arg2_p, &self->status_code, &self->headers, &self->content);
111 
112     if (rc == -1) {
113         self->headers = zhash_new ();
114         zhash_autofree (self->headers);
115 
116         return -1;
117     }
118 
119     self->free_content = self->content != NULL;
120 
121     if (result != 0) {
122         zhash_destroy(&self->headers);
123         self->headers = zhash_new ();
124         zhash_autofree (self->headers);
125 
126         errno = result;
127         return -1;
128     }
129 
130     return 0;
131 }
132 
133 const char *
zhttp_response_content_type(zhttp_response_t * self)134 zhttp_response_content_type (zhttp_response_t *self) {
135     assert (self);
136 
137     return (const char*)zhash_lookup (self->headers, "Content-Type");
138 }
139 
140 
141 void
zhttp_response_set_content_type(zhttp_response_t * self,const char * content_type)142 zhttp_response_set_content_type (zhttp_response_t *self, const char* content_type) {
143     assert (self);
144     zhash_insert (self->headers, "Content-Type", (void*) content_type);
145 }
146 
147 
148 uint32_t
zhttp_response_status_code(zhttp_response_t * self)149 zhttp_response_status_code (zhttp_response_t *self) {
150     assert (self);
151 
152     return self->status_code;
153 }
154 
155 
156 void
zhttp_response_set_status_code(zhttp_response_t * self,uint32_t status_code)157 zhttp_response_set_status_code (zhttp_response_t *self, uint32_t status_code) {
158     assert (self);
159 
160     self->status_code = status_code;
161 }
162 
163 
164 zhash_t *
zhttp_response_headers(zhttp_response_t * self)165 zhttp_response_headers (zhttp_response_t *self) {
166     assert (self);
167 
168     return self->headers;
169 }
170 
171 
172 size_t
zhttp_response_content_length(zhttp_response_t * self)173 zhttp_response_content_length (zhttp_response_t *self) {
174     assert (self);
175 
176     if (!self->content)
177         return 0;
178 
179     return strlen (self->content);
180 }
181 
182 const char *
zhttp_response_content(zhttp_response_t * self)183 zhttp_response_content (zhttp_response_t *self) {
184     assert (self);
185 
186     return self->content;
187 }
188 
189 
190 char *
zhttp_response_get_content(zhttp_response_t * self)191 zhttp_response_get_content (zhttp_response_t *self) {
192     assert (self);
193 
194 
195     if (self->content == NULL)
196         return NULL;
197 
198     char* content = self->content;
199 
200     // If the we don't own the content we can move the ownership, so we must duplicate the content
201     if (!self->free_content)
202         content = strdup (content);
203 
204     self->content = NULL;
205     self->free_content = false;
206 
207     return content;
208 }
209 
210 void
zhttp_response_set_content(zhttp_response_t * self,char ** content)211 zhttp_response_set_content (zhttp_response_t *self, char **content) {
212     assert (self);
213     assert (content);
214 
215     if (self->free_content)
216         zstr_free (&self->content);
217 
218     self->free_content = true;
219     self->content = *content;
220     *content = NULL;
221 }
222 
223 
224 void
zhttp_response_set_content_const(zhttp_response_t * self,const char * content)225 zhttp_response_set_content_const (zhttp_response_t *self, const char *content) {
226     assert (self);
227     assert (content);
228 
229     if (self->free_content)
230         zstr_free (&self->content);
231 
232     self->free_content = false;
233     self->content = (char*) content;
234 }
235 
236 
237 void
zhttp_response_reset_content(zhttp_response_t * self)238 zhttp_response_reset_content (zhttp_response_t *self) {
239     assert (self);
240 
241     if (self->free_content)
242         zstr_free (&self->content);
243 
244     self->free_content = false;
245     self->content = NULL;
246 }
247 
248 void
zhttp_response_test(bool verbose)249 zhttp_response_test (bool verbose) {
250 
251 }
252