Adaptive Framework  0.9.0
All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
afw_server_fcgi_request.c
Go to the documentation of this file.
1 // See the 'COPYING' file in the project root for licensing information.
2 /*
3  * Implementation of afw_request interface
4  *
5  * Copyright (c) 2010-2023 Clemson University
6  *
7  */
8 
9 
15 /* This header has to be first because it includes fcgi_stdio.h. */
17 #include "afw.h"
18 
19 
20 /* Declares and rti/inf defines for interface afw_request */
21 #define AFW_IMPLEMENTATION_ID "afw_server_fcgi"
22 #define AFW_IMPLEMENTATION_SPECIFIC NULL /* Change to &label if needed. */
24 
25 
26 static afw_size_t
27 impl_read_content_cb(
28  void *context,
29  const void * buffer,
30  afw_size_t size,
31  afw_boolean_t *more_to_read,
32  const afw_pool_t *p,
33  afw_xctx_t *xctx)
34 {
35  afw_size_t size_read;
36 
37  impl_afw_request_read_raw_request_body(
38  (const afw_request_t *)context,
39  size, (void *)buffer, &size_read, more_to_read, xctx);
40 
41  return size_read;
42 }
43 
44 
45 static afw_size_t
46 impl_write_content_cb(
47  void *context,
48  const void * buffer,
49  afw_size_t size,
50  const afw_pool_t *p,
51  afw_xctx_t *xctx)
52 {
53  impl_afw_request_write_raw_response_body(
54  (const afw_request_t *)context, size, buffer, xctx);
55 
56  return size;
57 }
58 
59 
60 /* Create an adaptive object in memory. */
64  FCGX_Request *fcgx_request,
65  afw_xctx_t *xctx)
66 {
68  const afw_value_t *value;
69  const afw_utf8_z_t *length_z;
70  const afw_utf8_octet_t *c;
71  afw_size_t len;
72 
73  /* Allocate memory for self. */
75 
76  /* Initialize Self. */
77  self->pub.inf = &impl_afw_request_inf;
78  self->pub.xctx = xctx;
79  self->fcgx_request = fcgx_request;
80  self->server = server;
81  self->pub.read_content_cb = impl_read_content_cb;
82  self->pub.write_content_cb = impl_write_content_cb;
83 
84  /* Create properties object and request:: qualifier. */
86  self, xctx);
87  afw_runtime_xctx_set_object(self->pub.properties, true, xctx);
88  afw_xctx_push_qualifier_object(&afw_s_request, self->pub.properties,
89  true, xctx->p, xctx);
90 
91  /* Set environment object and qualifier. */
92  afw_runtime_xctx_set_object(server->environment_variables_object,
93  true, xctx);
94  afw_xctx_push_qualifier_object(&afw_s_environment,
95  server->environment_variables_object, true, xctx->p, xctx);
96 
97  /* Get request method. */
98  value = afw_object_get_property(self->pub.properties,
100  if (!value) {
101  AFW_THROW_ERROR_Z(general,
102  AFW_REQUEST_Q_PN_REQUEST_METHOD " property required.", xctx);
103  }
104  self->pub.method = afw_value_as_utf8(value, xctx->p, xctx);
105 
106  /* Get request URI. */
107  self->pub.uri = afw_object_old_get_property_as_utf8(self->pub.properties,
108  &AFW_REQUEST_s_PN_PATH_INFO, xctx->p, xctx);
109  if (!self->pub.uri || self->pub.uri->len == 0) {
110  self->pub.uri = afw_object_old_get_property_as_utf8(self->pub.properties,
111  &AFW_REQUEST_s_PN_REQUEST_URI, xctx->p, xctx);
112  if (self->pub.uri && self->pub.uri->len != 0) {
113  for (c = self->pub.uri->s, len = self->pub.uri->len;
114  len > 0; c++, len--)
115  {
116  if (*c == '?') {
117  self->pub.uri = afw_utf8_create(
118  self->pub.uri->s, c - self->pub.uri->s,
119  xctx->p, xctx);
120  }
121  }
122  }
123  }
124  if (!self->pub.uri || self->pub.uri->len == 0) {
125  AFW_THROW_ERROR_Z(general,
127  " property required", xctx);
128  }
129 
130  /* Get request query string. */
131  value = afw_object_get_property(self->pub.properties,
133  if (!value) {
134  AFW_THROW_ERROR_Z(general,
135  AFW_REQUEST_Q_PN_QUERY_STRING " property required.", xctx);
136  }
137  self->pub.query_string = afw_value_as_utf8(value, xctx->p, xctx);
138 
139  /* Get request content type. */
140  self->pub.content_type = afw_object_old_get_property_as_utf8(
141  self->pub.properties,
142  &AFW_REQUEST_s_PN_CONTENT_TYPE, xctx->p, xctx);
143 
144  /* Get request content length. */
145  value = afw_object_get_property(self->pub.properties,
147  if (value) {
148  length_z = afw_value_as_utf8_z(value, xctx->p, xctx);
149  self->pub.content_length = atoi(length_z);
150  }
151 
152  /* Get request accept header. */
153  value = afw_object_get_property(self->pub.properties,
155  if (value) {
156  self->pub.accept = afw_utf8_parse_csv(
157  afw_value_as_utf8(value, xctx->p, xctx),
158  xctx->p, xctx);
159  }
160 
161  /* Return new adaptor. */
162  return self;
163 }
164 
165 
166 
167 /*
168  * Implementation of method release of interface afw_request.
169  */
170 void
171 impl_afw_request_release(
172  const afw_request_t * instance,
173  afw_xctx_t *xctx)
174 {
175  /*
176  * Continue release, even if there is already an error. Don't overwrite
177  * existing error.
178  */
179 
180  /* Resource will be release when execution context (xctx) is released. */
181 }
182 
183 
184 
185 /*
186  * Implementation of method set_error_info of interface afw_request.
187  */
188 void
189 impl_afw_request_set_error_info(
190  const afw_request_t * instance,
191  const afw_object_t * error_info,
192  afw_xctx_t *xctx)
193 {
196 
197  self->pub.error_info = error_info;
198 }
199 
200 
201 
202 /*
203  * Implementation of method read_request_body of interface afw_request.
204  */
205 void
206 impl_afw_request_read_raw_request_body(
207  const afw_request_t * instance,
208  afw_size_t buffer_size,
209  void * buffer,
210  afw_size_t * size,
211  afw_boolean_t * more_to_read,
212  afw_xctx_t *xctx)
213 {
216  int c;
217  unsigned char *b = buffer;
218 
219  /* Make sure in correct state then set it. */
220  if (self->state > afw_request_state_content_read) {
221  AFW_THROW_ERROR_Z(general,
222  "read_request_body() called out of order", xctx);
223  }
224  self->state = afw_request_state_content_read;
225 
226 
227  /* Read into buffer until buffer full or EOF. */
228  *more_to_read = 1;
229  for (*size = 0; *size < buffer_size; (*size)++) {
230  c = FCGX_GetChar(self->fcgx_request->in);
231  if (c == EOF) {
232  *more_to_read = 0;
233  break;
234  }
235  *(b++) = c;
236  }
237 }
238 
239 
240 
241 /*
242  * Implementation of method set_response_status_code of interface afw_request.
243  */
244 void
245 impl_afw_request_set_response_status_code(
246  const afw_request_t * instance,
247  const afw_utf8_t * code,
248  const afw_utf8_t * reason,
249  afw_xctx_t *xctx)
250 {
253  int rv = 0;
254 
255  /* Ignore status if already past state. */
256  if (self->state >= afw_request_state_status_set) {
257  return;
258  }
259  self->state = afw_request_state_status_set;
260 
261  /*
262  * Set response status. This is done in FastCGI by setting a "Status"
263  * header that is examined but not sent to the client client.
264  */
265  if (reason) {
266  rv = FCGX_FPrintF(self->fcgx_request->out,
267  "Status:%" AFW_UTF8_FMT " %" AFW_UTF8_FMT
268  AFW_CRLF,
269  AFW_UTF8_FMT_ARG(code), AFW_UTF8_FMT_ARG(reason));
270  }
271  else {
272  rv = FCGX_FPrintF(self->fcgx_request->out,
273  "Status:%" AFW_UTF8_FMT AFW_CRLF,
274  AFW_UTF8_FMT_ARG(code));
275  }
276  if (rv == -1) {
277  AFW_THROW_ERROR_Z(general,
278  "FCGX_FPrintF() failed", xctx);
279  }
280 }
281 
282 
283 
284 /*
285  * Implementation of method write_response_header of interface afw_request.
286  */
287 void
288 impl_afw_request_write_response_header(
289  const afw_request_t * instance,
290  const afw_utf8_t * name,
291  const afw_utf8_t * value,
292  afw_xctx_t *xctx)
293 {
296  int rv;
297 
298  /* Make sure in correct state then set it. */
299  if (self->state > afw_request_state_header_written) {
300  AFW_THROW_ERROR_Z(general,
301  "write_response_header() called out of order", xctx);
302  }
303  self->state = afw_request_state_header_written;
304 
305  /* Write response header */
306  rv = FCGX_FPrintF(self->fcgx_request->out,
308  AFW_UTF8_FMT_ARG(name), AFW_UTF8_FMT_ARG(value));
309  if (rv == -1) {
310  AFW_THROW_ERROR_Z(general,
311  "FCGX_FPrintF() failed.", xctx);
312  }
313 }
314 
315 
316 
317 /*
318  * Implementation of method write_response_body of interface afw_request.
319  */
320 void
321 impl_afw_request_write_raw_response_body(
322  const afw_request_t * instance,
323  apr_size_t size,
324  const void * buffer,
325  afw_xctx_t *xctx)
326 {
329  apr_size_t remaining;
330  const char *next;
331  int rv;
332  int n;
333 
334  /* Make sure in correct state. */
335  if (self->state > afw_request_state_response_written) {
336  AFW_THROW_ERROR_Z(general,
337  "write_response_body() called out of order", xctx);
338  }
339 
340  /* If this is the first write_response, write AFW_CRLF. */
341  if (self->state < afw_request_state_response_written) {
342  rv = FCGX_PutStr(AFW_CRLF, AFW_CRLF_STRLEN,
343  self->fcgx_request->out);
344  if (rv == -1) {
345  AFW_THROW_ERROR_RV_Z(client_closed, fcgi, rv,
346  "FCGX_PutStr() failed", xctx);
347  }
348  }
349 
350  /* Set state*/
351  self->state = afw_request_state_response_written;
352 
353  /* Write response. */
354  for (next = (const char *)buffer, remaining = size;
355  remaining > 0;
356  next = next + n,
357  remaining = remaining - n)
358  {
359  n = (remaining > INT_MAX) ? INT_MAX : (int)remaining;
360  rv = FCGX_PutStr(next, n, self->fcgx_request->out);
361  if (rv == -1) {
362  AFW_THROW_ERROR_RV_Z(client_closed, fcgi, rv,
363  "FCGX_PutStr() failed", xctx);
364  }
365  }
366 }
367 
368 
369 
370 /*
371  * Implementation of method flush_response of interface afw_request.
372  */
373 void
374 impl_afw_request_flush_response(
375  const afw_request_t * instance,
376  afw_xctx_t *xctx)
377 {
380  int rv;
381 
382  rv = FCGX_FFlush(self->fcgx_request->out);
383  if (rv == -1) {
384  AFW_THROW_ERROR_RV_Z(client_closed, fcgi, rv,
385  "FCGX_FFlush() failed", xctx);
386  }
387 }
388 
389 
390 
391 /*
392  * Implementation of method finish_response of interface afw_request.
393  */
394 void
395 impl_afw_request_finish_response(
396  const afw_request_t * instance,
397  afw_xctx_t *xctx)
398 {
399  int rv;
400 
403 
404  /* If there was no write_response, write AFW_CRLF. */
405  if (self->state < afw_request_state_response_written) {
406  rv = FCGX_PutStr(AFW_CRLF, AFW_CRLF_STRLEN,
407  self->fcgx_request->out);
408  if (rv == -1) {
409  AFW_THROW_ERROR_RV_Z(client_closed, fcgi, rv,
410  "FCGX_PutStr() failed", xctx);
411  }
412  }
413 
414  /* Make sure in correct state then set it. */
415  if (self->state >= afw_request_state_response_finished) {
416  AFW_THROW_ERROR_Z(general,
417  "finish_response() called out of order", xctx);
418  }
419  self->state = afw_request_state_response_finished;
420 
421  /*
422  * FCGX_FFlush documents that this is not necessary. It is left here
423  * commented out. It might be needed for server-push.
424  */
425  rv = FCGX_FFlush(self->fcgx_request->out);
426  if (rv == -1) {
427  AFW_THROW_ERROR_RV_Z(client_closed, fcgi, rv,
428  "FCGX_FFlush() failed", xctx);
429  }
430 }
Adaptive Framework Core API.
Interface afw_interface implementation declares.
Internal header file for AFW FCGI Server.
const afw_object_t * afw_server_fcgi_internal_create_properties_object(afw_server_fcgi_internal_request_t *request, afw_xctx_t *xctx)
afw_server_fcgi_internal_request_t * afw_server_fcgi_internal_create_request(afw_server_fcgi_internal_t *server, FCGX_Request *fcgx_request, afw_xctx_t *xctx)
#define AFW_UTF8_FMT_ARG(A_STRING)
Convenience Macro for use with AFW_UTF8_FMT to specify arg.
Definition: afw_common.h:605
_Bool afw_boolean_t
Definition: afw_common.h:373
#define AFW_UTF8_FMT
Format string specifier used for afw_utf8_t.
Definition: afw_common.h:588
afw_utf8_octet_t afw_utf8_z_t
NFC normalized UTF-8 null terminated string.
Definition: afw_common.h:523
char afw_utf8_octet_t
8 bits of utf-8 codepoint.
Definition: afw_common.h:236
apr_size_t afw_size_t
size_t.
Definition: afw_common.h:151
#define AFW_CRLF
Definition: afw_common.h:396
#define AFW_CRLF_STRLEN
Definition: afw_common.h:400
#define AFW_THROW_ERROR_RV_Z(code, rv_source_id, rv, message_z, xctx)
Macro used to set error and rv in xctx and throw it.
Definition: afw_error.h:301
#define AFW_THROW_ERROR_Z(code, message_z, xctx)
Macro used to set error and 0 rv in xctx and throw it.
Definition: afw_error.h:283
#define afw_object_get_property(instance, property_name, xctx)
Call method get_property of interface afw_object.
afw_object_old_get_property_as_utf8(const afw_object_t *instance, const afw_utf8_t *property_name, const afw_pool_t *p, afw_xctx_t *xctx)
Get an object's property value as a string in specified pool.
Definition: afw_object.c:531
#define AFW_REQUEST_Q_PN_REQUEST_URI
Request property name REQUEST_URI quoted string.
Definition: afw_request.h:113
#define AFW_REQUEST_Q_PN_PATH_INFO
Request property name PATH_INFO quoted string.
Definition: afw_request.h:69
#define AFW_REQUEST_s_PN_QUERY_STRING
Request property name QUERY_STRING afw_utf8_t.
Definition: afw_request.h:90
#define AFW_REQUEST_Q_PN_QUERY_STRING
Request property name QUERY_STRING quoted string.
Definition: afw_request.h:83
#define AFW_REQUEST_s_PN_CONTENT_TYPE
Request property name CONTENT_TYPE afw_utf8_t.
Definition: afw_request.h:40
#define AFW_REQUEST_s_PN_PATH_INFO
Request property name PATH_INFO afw_utf8_t.
Definition: afw_request.h:76
#define AFW_REQUEST_s_PN_REQUEST_URI
Request property name REQUEST_URI afw_utf8_t.
Definition: afw_request.h:120
#define AFW_REQUEST_s_PN_REQUEST_METHOD
Request accept header REQUEST_METHOD afw_utf8_t.
Definition: afw_request.h:106
#define AFW_REQUEST_Q_PN_REQUEST_METHOD
Request property name REQUEST_METHOD quoted string.
Definition: afw_request.h:98
#define AFW_REQUEST_s_PN_CONTENT_LENGTH
Request property name CONTENT_LENGTH afw_utf8_t.
Definition: afw_request.h:52
#define AFW_REQUEST_s_PN_HTTP_ACCEPT
Request property name HTTP_ACCEPT afw_utf8_t.
Definition: afw_request.h:62
afw_runtime_xctx_set_object(const afw_object_t *object, afw_boolean_t overwrite, afw_xctx_t *xctx)
Set an object pointer in the xctx's runtime objects.
Definition: afw_runtime.c:292
afw_utf8_parse_csv(const afw_utf8_t *s, const afw_pool_t *p, afw_xctx_t *xctx)
Check to see if a string equals a utf8_z string.
Definition: afw_utf8.c:1149
#define afw_utf8_create(s, len, p, xctx)
Create utf-8 string without copy unless necessary in pool specified.
Definition: afw_utf8.h:239
afw_value_as_utf8(const afw_value_t *value, const afw_pool_t *p, afw_xctx_t *xctx)
Definition: afw_value.c:456
afw_value_as_utf8_z(const afw_value_t *value, const afw_pool_t *p, afw_xctx_t *xctx)
Definition: afw_value.c:315
afw_xctx_push_qualifier_object(const afw_utf8_t *qualifier_name, const afw_object_t *qualifier_object, afw_boolean_t secure, const afw_pool_t *p, afw_xctx_t *xctx)
Push qualifier object on to stack.
Definition: afw_xctx.c:406
#define afw_xctx_calloc_type(type, xctx)
Macro to allocate cleared memory to hold type in xctx's pool.
Definition: afw_xctx.h:199
Interface afw_object public struct.
Interface afw_pool public struct.
Interface afw_request public struct.
NFC normalized UTF-8 string.
Definition: afw_common.h:545
Interface afw_value public struct.
Interface afw_xctx public struct.