Adaptive Framework  0.9.0
All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
afw_request.c
Go to the documentation of this file.
1 // See the 'COPYING' file in the project root for licensing information.
2 /*
3  * Adaptive Framework Request.
4  *
5  * Copyright (c) 2010-2023 Clemson University
6  *
7  */
8 
9 
15 #include "afw_internal.h"
16 
17 /* Declares and rti/inf defines for interface afw_content_type */
18 #define AFW_IMPLEMENTATION_ID "request"
20 
21 
22 /* Self typedef for application/afw implementation of afw_stream. */
23 typedef struct
25  afw_stream_t pub;
26 
27  /* Private implementation variables */
28  const afw_request_t *request;
29 
31 
32 
33 
34 /* Get response content type. */
35 AFW_DEFINE(void)
36 afw_request_get_response_content_type(
37  const afw_request_t *instance,
38  const afw_content_type_t **response_content_type,
39  const afw_utf8_t **type,
40  const afw_utf8_t **type_parameter,
41  afw_xctx_t *xctx)
42 {
43  const afw_utf8_t *const *accept;
44 
45  *response_content_type = NULL;
46  *type_parameter = NULL;
47 
48  /* If accept was not specified, default to application/json. */
49  if (!instance->accept || !*instance->accept) {
50  *type = &AFW_JSON_S_CONTENT_TYPE;
51  *response_content_type = afw_environment_get_content_type(
52  &AFW_JSON_S_CONTENT_TYPE, xctx);
53  }
54 
55  /* It accept specified, find first first one with registered handler. */
56  /*NOTE: This does not process wildcard or q= properly. */
57  else {
58  for (accept = instance->accept; accept && *accept; accept++) {
59  if (!afw_utf8_compare(*accept, &afw_s_a_star_slash_star)) {
60  // if */* is specified, use default of application/json
61  *type = &AFW_JSON_S_CONTENT_TYPE;
62  *response_content_type = afw_environment_get_content_type(
63  &AFW_JSON_S_CONTENT_TYPE, xctx);
64  break;
65  } else {
66  *response_content_type = afw_environment_get_content_type(
67  *accept, xctx);
68 
69  if (*response_content_type) {
70  *type = *accept;
71  break;
72  }
73  }
74  }
75  }
76 
77  /* If an accept was specified but none match, throw error. */
78  if (!*response_content_type) {
79  *response_content_type = afw_environment_get_content_type(
80  &AFW_JSON_S_CONTENT_TYPE, xctx);
81  AFW_THROW_ERROR_Z(unsupported_accept, "Unsupported accept.", xctx);
82  }
83 }
84 
85 
86 /* Get response content type. */
88 afw_request_prepare_response_content_type(
89  const afw_request_t * instance, afw_xctx_t *xctx)
90 {
91  afw_request_t *self = (afw_request_t *)instance;
92  const afw_content_type_t *response_content_type;
93  const afw_utf8_t *type;
94  const afw_utf8_t *type_parameter;
95 
96  /* If already obtained, just return it. */
97  if (instance->response_content_type) {
98  return instance->response_content_type;
99  }
100 
101  afw_request_get_response_content_type(instance,
102  &response_content_type, &type, &type_parameter, xctx);
103 
104  /* Get content type. */
105  self->response_content_type = response_content_type;
106 
107  /* Write response_content_type header. */
109  &afw_s_a_Content_dash_Type,
110  type,
111  xctx);
112 
113  /* Return content type. */
114  return self->response_content_type;
115 }
116 
117 
118 /* Read a request body into a string in a specifed pool. */
119 AFW_DEFINE(const afw_utf8_t *)
121  const afw_request_t * instance,
122  const afw_pool_t *p,
123  afw_xctx_t *xctx)
124 {
125  afw_utf8_z_t *buffer_z;
126  afw_utf8_z_t *cursor_z;
127  afw_boolean_t more;
128  afw_size_t read;
129 
130 
132  if (instance->content_length <= 0) return NULL;
133 
134  /* Read request body into string and return. */
135  buffer_z = afw_pool_calloc(p, instance->content_length, xctx);
136  cursor_z = buffer_z;
137  read = 0;
138  do {
139  cursor_z += read;
141  instance->content_length, cursor_z,
142  &read, &more, xctx);
143  } while (more);
144  return afw_utf8_create(buffer_z, instance->content_length, p, xctx);
145 }
146 
147 /* Read a request body to value a specifed pool. */
148 AFW_DEFINE(const afw_value_t *)
150  const afw_request_t * instance,
151  const afw_pool_t *p,
152  afw_xctx_t *xctx)
153 {
154  const afw_utf8_t *string;
155  const afw_content_type_t *content_type;
156  afw_utf8_t content_type_id;
157  const afw_utf8_octet_t *s;
158  const afw_utf8_octet_t *end;
159 
160  string = afw_request_body_to_utf8(instance, p, xctx);
161  if (!string) return NULL;
162 
163  for (s = instance->content_type->s, end = s + instance->content_type->len;
164  s < end && *s != ';' && *s != ' ';
165  s++);
166 
167  content_type_id.s = instance->content_type->s;
168  content_type_id.len = s - instance->content_type->s;
169 
172  content_type = afw_environment_get_content_type(
173  &content_type_id, xctx);
174  if (!content_type) {
175  AFW_THROW_ERROR_FZ(general, xctx,
176  "Unsupported content-type %" AFW_UTF8_FMT ".",
177  AFW_UTF8_FMT_ARG(instance->content_type));
178  }
179 
180  return afw_content_type_raw_to_value(content_type,
181  afw_utf8_as_raw(string, xctx->p, xctx), &afw_s_a_request_body,
182  xctx->p, xctx);
183 }
184 
185 /* Write value to response body. */
186 AFW_DECLARE(void)
188  const afw_request_t * instance,
189  const afw_value_t *value,
190  const afw_object_options_t *options,
191  afw_xctx_t *xctx)
192 {
193  const afw_memory_t *raw;
194  const afw_content_type_t *response_content_type;
195  const afw_stream_t *writer;
196 
197  /* Get response content type. */
198  response_content_type = afw_request_prepare_response_content_type(instance, xctx);
199 
200  /* If closed, return. */
201  if (instance->is_closed) {
202  return;
203  }
204 
205  /* Write encoded content. */
206  raw = afw_content_type_value_to_raw(response_content_type, value, options,
207  xctx->p, xctx);
208  writer = afw_stream_standard(response_body, xctx);
209  writer->write_cb((void *)writer, raw->ptr, raw->size, xctx->p, xctx);
210  afw_stream_flush(writer, xctx);
211 }
212 
213 
214 /* Write xctx error to response body. */
215 AFW_DEFINE(void)
217  const afw_request_t * instance,
218  const afw_utf8_t *code,
219  const afw_error_t *error,
220  afw_xctx_t *xctx)
221 {
222  const afw_object_t *response;
223  const afw_value_t *value;
224  const afw_object_t *err;
225 
226  afw_request_set_response_status_code(instance, code, NULL, xctx);
227 
228  /* If response should not include error object, skip writing it. */
229  if (!afw_error_allow_in_response(error->code)) {
230  ((afw_request_t *)instance)->is_closed = true;
231  return;
232  }
233 
234  response = instance->error_info;
235  if (!response) {
236  response = afw_object_create_managed(xctx->p, xctx);
237  }
238  afw_object_set_property_as_string(response, &afw_s_status, &afw_s_error, xctx);
239  err = afw_object_create_embedded(response, &afw_s_error, xctx);
240  afw_error_add_to_object(err, error, xctx);
241  value = afw_value_create_object(response, xctx->p, xctx);
242  afw_request_write_value_to_response_body(instance, value, NULL, xctx);
243 }
244 
245 
246 /* Write simple success to response body. */
247 AFW_DEFINE(void)
249  const afw_request_t * instance,
250  const afw_object_t * response,
251  afw_xctx_t *xctx)
252 {
253  const afw_value_t *value;
254 
255  afw_request_set_response_status_code(instance, &afw_s_200,
256  &afw_s_OK, xctx);
257 
258  /* If response is NULL, make empty one. */
259  if (!response) {
260  response = afw_object_create_managed(xctx->p, xctx);
261  }
262 
263  /* Default status to success. */
264  if (!afw_object_has_property(response, &afw_s_status, xctx)) {
265  afw_object_set_property_as_string(response, &afw_s_status,
266  &afw_s_success, xctx);
267  }
268 
269  /* Write response to body. */
270  value = afw_value_create_object(response, xctx->p, xctx);
271  afw_request_write_value_to_response_body(instance, value, NULL, xctx);
272 }
273 
274 
275 
276 static afw_size_t
277 impl_response_write_cb(
278  void *context,
279  const void *buffer,
280  afw_size_t size,
281  const afw_pool_t *p,
282  afw_xctx_t *xctx)
283 {
286 
287  afw_request_write_raw_response_body(self->request, size, buffer, xctx);
288 
289  return size;
290 }
291 
292 /*
293  * Implementation of method release for interface afw_stream.
294  */
295 void
296 impl_afw_stream_release(
297  const afw_stream_t *instance,
298  afw_xctx_t *xctx)
299 {
302 
303  impl_afw_stream_flush(instance, xctx);
304  afw_pool_release(self->pub.p, xctx);
305 }
306 
307 /*
308  * Implementation of method read for interface afw_stream.
309  */
310 void
312  const afw_stream_t *instance,
313  const void *buffer,
314  afw_size_t size,
315  afw_xctx_t *xctx)
316 {
318  AFW_THROW_ERROR_Z(general, "Method not implemented.", xctx);
319 }
320 
321 /*
322  * Implementation of method flush for interface afw_stream.
323  */
324 void
325 impl_afw_stream_flush(
326  const afw_stream_t *instance,
327  afw_xctx_t *xctx)
328 {
331 
332  afw_request_flush_response(self->request, xctx);
333 }
334 
335 /*
336  * Implementation of method write for interface afw_stream.
337  */
338 void
339 impl_afw_stream_write(
340  const afw_stream_t *instance,
341  const void *buffer,
342  afw_size_t size,
343  afw_xctx_t *xctx)
344 {
345  if (size == 0) {
346  return;
347  }
348 
349  impl_response_write_cb((void *)instance, buffer, size,
350  xctx->p, xctx);
351 }
352 
353 AFW_DEFINE(const afw_stream_t *)
354 afw_request_response_body_raw_writer_create(
355  const afw_request_t *request,
356  afw_xctx_t *xctx)
357 {
359 
360  self = afw_pool_calloc_type(xctx->p,
362  self->pub.inf = &impl_afw_stream_inf;
363  self->pub.p = xctx->p;
364  self->pub.streamId = &afw_s_raw_response_body;
365  self->pub.write_cb = &impl_response_write_cb;
366  self->request = request;
367 
368  return (const afw_stream_t *)self;
369 }
AFW_DEFINE(const afw_object_t *)
#define AFW_DECLARE(type)
Declare a public afw function.
Adaptive Framework Core Internal.
Interface afw_interface implementation declares.
afw_value_create_object(const afw_object_t *internal, const afw_pool_t *p, afw_xctx_t *xctx)
Create function for unmanaged data type object value.
afw_object_set_property_as_string(const afw_object_t *object, const afw_utf8_t *property_name, const afw_utf8_t *internal, afw_xctx_t *xctx)
Set property function for data type string values.
#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_content_type_raw_to_value(instance, raw, source_location, p, xctx)
Call method raw_to_value of interface afw_content_type.
afw_content_type_value_to_raw(const afw_content_type_t *instance, const afw_value_t *value, const afw_object_options_t *options, const afw_pool_t *p, afw_xctx_t *xctx)
Convert value to the raw in specified pool.
const afw_content_type_t * afw_environment_get_content_type(const afw_utf8_t *type, afw_xctx_t *xctx)
Get the afw_content_type struct associated with a content type.
void afw_error_add_to_object(const afw_object_t *object, const afw_error_t *error, afw_xctx_t *xctx)
Add error info to existing object using specified pool.
Definition: afw_error.c:862
#define AFW_THROW_ERROR_FZ(code, xctx, format_z,...)
Macro used to set error and 0 rv in xctx and throw it.
Definition: afw_error.h:319
afw_error_allow_in_response(afw_error_code_t code)
Determine if the error object for code is allowed in HTTP response.
Definition: afw_error.c:1082
#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_has_property(instance, property_name, xctx)
Call method has_property of interface afw_object.
#define afw_object_create_managed(p, xctx)
Create an empty entity object in its own pool.
Definition: afw_object.h:913
const afw_object_t * afw_object_create_embedded(const afw_object_t *embedding_object, const afw_utf8_t *property_name, afw_xctx_t *xctx)
Create an empty embedded object in a memory object.
#define afw_pool_calloc(instance, size, xctx)
Call method calloc of interface afw_pool.
#define afw_pool_release(instance, xctx)
Call method release of interface afw_pool.
#define afw_pool_calloc_type(instance, type, xctx)
Macro to allocate cleared memory to hold type in pool.
Definition: afw_pool.h:167
#define afw_request_write_raw_response_body(instance, size, buffer, xctx)
Call method write_raw_response_body of interface afw_request.
#define afw_request_flush_response(instance, xctx)
Call method flush_response of interface afw_request.
#define afw_request_set_response_status_code(instance, code, reason, xctx)
Call method set_response_status_code of interface afw_request.
#define afw_request_write_response_header(instance, name, value, xctx)
Call method write_response_header of interface afw_request.
#define afw_request_read_raw_request_body(instance, buffer_size, buffer, size, more_to_read, xctx)
Call method read_raw_request_body of interface afw_request.
afw_request_body_to_value(const afw_request_t *instance, const afw_pool_t *p, afw_xctx_t *xctx)
Read a request body to value in a specifed pool.
Definition: afw_request.c:149
void afw_request_write_value_to_response_body(const afw_request_t *instance, const afw_value_t *value, const afw_object_options_t *options, afw_xctx_t *xctx)
Write value to response body.
Definition: afw_request.c:187
afw_request_body_to_utf8(const afw_request_t *instance, const afw_pool_t *p, afw_xctx_t *xctx)
Read a request body into a utf-8 string in a specifed pool.
Definition: afw_request.c:120
afw_request_write_error_to_response_body(const afw_request_t *instance, const afw_utf8_t *code, const afw_error_t *error, afw_xctx_t *xctx)
Write xctx error to response body.
Definition: afw_request.c:216
afw_request_write_success_response(const afw_request_t *instance, const afw_object_t *response, afw_xctx_t *xctx)
Write simple success to response body.
Definition: afw_request.c:248
void impl_afw_stream_read(const afw_stream_t *instance, const void *buffer, afw_size_t size, afw_xctx_t *xctx)
Definition: afw_request.c:311
#define afw_stream_flush(instance, xctx)
Call method flush of interface afw_stream.
#define afw_stream_standard(enum_suffix, xctx)
Get xctx stream instance.
Definition: afw_stream.h:122
const afw_memory_t * afw_utf8_as_raw(const afw_utf8_t *string, const afw_pool_t *p, afw_xctx_t *xctx)
Convert utf-8 string to raw in specified pool.
Definition: afw_utf8.h:181
int afw_utf8_compare(const afw_utf8_t *s1, const afw_utf8_t *s2)
Compare two strings.
#define afw_utf8_create(s, len, p, xctx)
Create utf-8 string without copy unless necessary in pool specified.
Definition: afw_utf8.h:239
Interface afw_content_type public struct.
Adaptive Framework Error.
Definition: afw_error.h:65
Struct for memory pointer and size.
Definition: afw_common.h:505
Struct for object processing options.
Interface afw_object public struct.
Interface afw_pool public struct.
Interface afw_request public struct.
Interface afw_stream public struct.
NFC normalized UTF-8 string.
Definition: afw_common.h:545
Interface afw_value public struct.
Interface afw_xctx public struct.