/**************************************************************************//** * Creates and populates a parameter list from a URI structure. * The list does not copy the parameter strings themselves, so the URI structure * must be retained (and its parameters unmodified) while the list is in use. * * @param uri The URI containing the parameters. * @return List created from the parameters of the URI, or NULL on error. */ static VC_CONTAINERS_LIST_T *fill_parameter_list(VC_URI_PARTS_T *uri) { uint32_t num_parameters = vc_uri_num_queries(uri); VC_CONTAINERS_LIST_T *parameters; uint32_t ii; parameters = vc_containers_list_create(num_parameters, sizeof(PARAMETER_T), (VC_CONTAINERS_LIST_COMPARATOR_T)parameter_comparator); if (!parameters) return NULL; for (ii = 0; ii < num_parameters; ii++) { PARAMETER_T param; vc_uri_query(uri, ii, ¶m.name, ¶m.value); if (!vc_containers_list_insert(parameters, ¶m, false)) { vc_containers_list_destroy(parameters); return NULL; } } #ifdef RTP_DEBUG vc_containers_list_validate(parameters); #endif return parameters; }
/**************************************************************************//** * Reads an HTTP response and parses it into headers and content. * The headers and content remain stored in the comms buffer, but referenced * by the module's header list. Content uses a special header name that cannot * occur in the real headers. * * @param p_ctx The HTTP reader context. * @return The resulting status of the function. */ static VC_CONTAINER_STATUS_T io_http_read_response(VC_CONTAINER_IO_T *p_ctx) { VC_CONTAINER_IO_MODULE_T *module = p_ctx->module; char *next_read = module->comms_buffer; size_t space_available = sizeof(module->comms_buffer) - 1; /* Allow for a NUL */ char *ptr = next_read; bool end_response = false; HTTP_HEADER_T header; const char endstr[] = "\r\n\r\n"; int endcount = sizeof(endstr) - 1; int endchk = 0; vc_containers_list_reset(module->header_list); /* Response status line doesn't need to be stored, just checked */ header.name = NULL; header.value = next_read; /* * We need to read just a byte at a time to make sure that we just read the HTTP response and * no more. For example, if a GET operation was requested the file being fetched will also * be waiting to be read on the socket. */ while (space_available) { if (io_http_read_from_net(p_ctx, next_read, 1) != 1) break; next_read++; space_available--; if (next_read[-1] == endstr[endchk]) { if (++endchk == endcount) break; } else endchk = 0; } if (!space_available) { LOG_ERROR(NULL, "comms buffer too small for complete HTTP message (%d)", sizeof(module->comms_buffer)); return VC_CONTAINER_ERROR_CORRUPTED; } *next_read = '\0'; if (endchk == endcount) { if (ENABLE_HTTP_EXTRA_LOGGING) LOG_DEBUG(NULL, "READ FROM SERVER: %d bytes\n%s\n-----------------------------------------", sizeof(module->comms_buffer) - 1 - space_available, module->comms_buffer); while (!end_response && ptr < next_read) { switch (*ptr) { case ':': if (header.value) { /* Just another character in the value */ ptr++; } else { /* End of name, expect value next */ *ptr++ = '\0'; header.value = ptr; } break; case '\n': if (header.value) { /* End of line while parsing the value part of the header, add name/value pair to list */ *ptr++ = '\0'; header.value = io_http_trim(header.value); if (header.name) { if (!vc_containers_list_insert(module->header_list, &header, false)) { LOG_ERROR(NULL, "HTTP: Failed to add <%s> header to list", header.name); return VC_CONTAINER_ERROR_OUT_OF_MEMORY; } } else { /* Check response status line */ if (!io_http_successful_response_status(header.value)) return VC_CONTAINER_ERROR_FORMAT_INVALID; } /* Ready for next header */ header.name = ptr; header.value = NULL; } else { /* End of line while parsing the name of a header */ *ptr++ = '\0'; if (*header.name && *header.name != '\r') { /* A non-empty name is invalid, so fail */ LOG_ERROR(NULL, "HTTP: Invalid name in header - no colon:\n%s", header.name); return VC_CONTAINER_ERROR_FORMAT_INVALID; } /* An empty name signifies the end of the HTTP response */ end_response = true; } break; default: /* Just another character in either the name or the value */ ptr++; } } } if (!space_available && !end_response) { /* Ran out of buffer space */ LOG_ERROR(NULL, "HTTP: Response header section too big"); return VC_CONTAINER_ERROR_FORMAT_INVALID; } return p_ctx->status; }