/*! * \brief Handles \ref event_session error processing. * * \internal * * \param session The \ref event_session object. * \param error The \ref event_session_error_type to handle. * \param ser HTTP TCP/TLS Server Session (\ref ast_tcptls_session_instance). * * \retval -1 Always returns -1. */ static int event_session_allocation_error_handler( struct event_session *session, enum event_session_error_type error, struct ast_tcptls_session_instance *ser) { /* Notify the client */ switch (error) { case ERROR_TYPE_STASIS_REGISTRATION: ast_http_error(ser, 500, "Internal Server Error", "Stasis registration failed"); break; case ERROR_TYPE_OOM: ast_http_error(ser, 500, "Internal Server Error", "Allocation failed"); break; case ERROR_TYPE_MISSING_APP_PARAM: ast_http_error(ser, 400, "Bad Request", "HTTP request is missing param: [app]"); break; case ERROR_TYPE_INVALID_APP_PARAM: ast_http_error(ser, 400, "Bad Request", "Invalid application provided in param [app]."); break; default: break; } /* Cleanup the session */ event_session_cleanup(session); return -1; }
int ast_ari_websocket_events_event_websocket_attempted(struct ast_tcptls_session_instance *ser, struct ast_variable *headers, struct ast_ari_events_event_websocket_args *args) { int res = 0; size_t i, j; int (* register_handler)(const char *, stasis_app_cb handler, void *data); ast_debug(3, "/events WebSocket attempted\n"); if (args->app_count == 0) { ast_http_error(ser, 400, "Bad Request", "Missing param 'app'"); return -1; } if (args->subscribe_all) { register_handler = &stasis_app_register_all; } else { register_handler = &stasis_app_register; } for (i = 0; i < args->app_count; ++i) { if (ast_strlen_zero(args->app[i])) { res = -1; break; } res |= register_handler(args->app[i], app_handler, NULL); } if (res) { for (j = 0; j < i; ++j) { stasis_app_unregister(args->app[j]); } ast_http_error(ser, 400, "Bad Request", "Invalid application provided in param 'app'."); } return res; }
static int http_post_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_vars, struct ast_variable *headers) { struct ast_variable *var; uint32_t ident; FILE *f; int content_len = 0; struct ast_str *post_dir; GMimeMessage *message; char *boundary_marker = NULL; if (method != AST_HTTP_POST) { ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method"); return 0; } if (!urih) { ast_http_error(ser, 400, "Missing URI handle", "There was an error parsing the request"); return 0; } ident = ast_http_manid_from_vars(headers); if (!ident || !astman_is_authed(ident)) { ast_http_request_close_on_completion(ser); ast_http_error(ser, 403, "Access Denied", "Sorry, I cannot let you do that, Dave."); return 0; } if (!astman_verify_session_writepermissions(ident, EVENT_FLAG_CONFIG)) { ast_http_request_close_on_completion(ser); ast_http_error(ser, 401, "Unauthorized", "You are not authorized to make this request."); return 0; } if (!(f = tmpfile())) { ast_log(LOG_ERROR, "Could not create temp file.\n"); ast_http_error(ser, 500, "Internal server error", "Could not create temp file."); return 0; } for (var = headers; var; var = var->next) { fprintf(f, "%s: %s\r\n", var->name, var->value); if (!strcasecmp(var->name, "Content-Length")) { if ((sscanf(var->value, "%30u", &content_len)) != 1) { ast_log(LOG_ERROR, "Invalid Content-Length in POST request!\n"); fclose(f); ast_http_request_close_on_completion(ser); ast_http_error(ser, 400, "Bad Request", "Invalid Content-Length in POST request!"); return 0; } ast_debug(1, "Got a Content-Length of %d\n", content_len); } else if (!strcasecmp(var->name, "Content-Type")) { boundary_marker = strstr(var->value, "boundary="); if (boundary_marker) { boundary_marker += strlen("boundary="); } } } fprintf(f, "\r\n"); /* * Always mark the body read as failed. * * XXX Should change readmimefile() to always be sure to read * the entire body so we can update the read status and * potentially keep the connection open. */ ast_http_body_read_status(ser, 0); if (0 > readmimefile(ser->stream, f, boundary_marker, content_len)) { ast_debug(1, "Cannot find boundary marker in POST request.\n"); fclose(f); ast_http_error(ser, 400, "Bad Request", "Cannot find boundary marker in POST request."); return 0; } if (fseek(f, SEEK_SET, 0)) { ast_log(LOG_ERROR, "Failed to seek temp file back to beginning.\n"); fclose(f); ast_http_error(ser, 500, "Internal server error", "Failed to seek temp file back to beginning."); return 0; } post_dir = urih->data; message = parse_message(f); /* Takes ownership and will close f */ if (!message) { ast_log(LOG_ERROR, "Error parsing MIME data\n"); ast_http_error(ser, 400, "Bad Request", "There was an error parsing the request."); return 0; } if (!process_message(message, ast_str_buffer(post_dir))) { ast_log(LOG_ERROR, "Invalid MIME data, found no parts!\n"); g_object_unref(message); ast_http_error(ser, 400, "Bad Request", "There was an error parsing the request."); return 0; } g_object_unref(message); /* XXX Passing 200 to the error response routine? */ ast_http_error(ser, 200, "OK", "File successfully uploaded."); return 0; }
static void *ast_httpd_helper_thread(void *data) { char buf[4096]; char cookie[4096]; char timebuf[256]; struct ast_http_server_instance *ser = data; struct ast_variable *vars = NULL; char *uri, *c, *title=NULL; int status = 200, contentlength = 0; time_t t; unsigned int static_content = 0; if (fgets(buf, sizeof(buf), ser->f)) { /* Skip method */ uri = buf; while(*uri && (*uri > 32)) uri++; if (*uri) { *uri = '\0'; uri++; } /* Skip white space */ while (*uri && (*uri < 33)) uri++; if (*uri) { c = uri; while (*c && (*c > 32)) c++; if (*c) { *c = '\0'; } } while (fgets(cookie, sizeof(cookie), ser->f)) { /* Trim trailing characters */ while(!ast_strlen_zero(cookie) && (cookie[strlen(cookie) - 1] < 33)) { cookie[strlen(cookie) - 1] = '\0'; } if (ast_strlen_zero(cookie)) break; if (!strncasecmp(cookie, "Cookie: ", 8)) { vars = parse_cookies(cookie); } } if (*uri) { if (!strcasecmp(buf, "get")) c = handle_uri(&ser->requestor, uri, &status, &title, &contentlength, &vars, &static_content); else c = ast_http_error(501, "Not Implemented", NULL, "Attempt to use unimplemented / unsupported method");\ } else c = ast_http_error(400, "Bad Request", NULL, "Invalid Request"); /* If they aren't mopped up already, clean up the cookies */ if (vars) ast_variables_destroy(vars); if (!c) c = ast_http_error(500, "Internal Error", NULL, "Internal Server Error"); if (c) { time(&t); strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&t)); ast_cli(ser->fd, "HTTP/1.1 %d %s\r\n", status, title ? title : "OK"); ast_cli(ser->fd, "Server: Asterisk/%s\r\n", ASTERISK_VERSION); ast_cli(ser->fd, "Date: %s\r\n", timebuf); ast_cli(ser->fd, "Connection: close\r\n"); if (!static_content) ast_cli(ser->fd, "Cache-Control: no-cache, no-store\r\n"); /* We set the no-cache headers only for dynamic content. * If you want to make sure the static file you requested is not from cache, * append a random variable to your GET request. Ex: 'something.html?r=109987734' */ if (contentlength) { char *tmp; tmp = strstr(c, "\r\n\r\n"); if (tmp) { ast_cli(ser->fd, "Content-length: %d\r\n", contentlength); if (write(ser->fd, c, (tmp + 4 - c)) < 0) { ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno)); } if (write(ser->fd, tmp + 4, contentlength) < 0) { ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno)); } } } else ast_cli(ser->fd, "%s", c); free(c); } if (title) free(title); } fclose(ser->f); free(ser); ast_atomic_fetchadd_int(&session_count, -1); return NULL; }
static char *handle_uri(struct sockaddr_in *sin, char *uri, int *status, char **title, int *contentlength, struct ast_variable **cookies, unsigned int *static_content) { char *c; char *turi; char *params; char *var; char *val; struct ast_http_uri *urih=NULL; int len; struct ast_variable *vars=NULL, *v, *prev = NULL; params = strchr(uri, '?'); if (params) { *params = '\0'; params++; while ((var = strsep(¶ms, "&"))) { val = strchr(var, '='); if (val) { *val = '\0'; val++; ast_uri_decode(val); } else val = ""; ast_uri_decode(var); if ((v = ast_variable_new(var, val))) { if (vars) prev->next = v; else vars = v; prev = v; } } } if (prev) prev->next = *cookies; else vars = *cookies; *cookies = NULL; ast_uri_decode(uri); if (!strncasecmp(uri, prefix, prefix_len)) { uri += prefix_len; if (!*uri || (*uri == '/')) { if (*uri == '/') uri++; ast_rwlock_rdlock(&uris_lock); urih = uris; while(urih) { len = strlen(urih->uri); if (!strncasecmp(urih->uri, uri, len)) { if (!uri[len] || uri[len] == '/') { turi = uri + len; if (*turi == '/') turi++; if (!*turi || urih->has_subtree) { uri = turi; break; } } } urih = urih->next; } if (!urih) ast_rwlock_unlock(&uris_lock); } } if (urih) { if (urih->static_content) *static_content = 1; c = urih->callback(sin, uri, vars, status, title, contentlength); ast_rwlock_unlock(&uris_lock); } else if (ast_strlen_zero(uri) && ast_strlen_zero(prefix)) { /* Special case: If no prefix, and no URI, send to /static/index.html */ c = ast_http_error(302, "Moved Temporarily", "Location: /static/index.html\r\n", "Redirecting to /static/index.html."); *status = 302; *title = strdup("Moved Temporarily"); } else { c = ast_http_error(404, "Not Found", NULL, "The requested URL was not found on this server."); *status = 404; *title = strdup("Not Found"); } ast_variables_destroy(vars); return c; }
static char *static_callback(struct sockaddr_in *req, const char *uri, struct ast_variable *vars, int *status, char **title, int *contentlength) { char result[4096]; char *c=result; char *path; char *ftype; const char *mtype; char wkspace[80]; struct stat st; int len; int fd; void *blob; /* Yuck. I'm not really sold on this, but if you don't deliver static content it makes your configuration substantially more challenging, but this seems like a rather irritating feature creep on Asterisk. */ if (!enablestatic || ast_strlen_zero(uri)) goto out403; /* Disallow any funny filenames at all */ if ((uri[0] < 33) || strchr("./|~@#$%^&*() \t", uri[0])) goto out403; if (strstr(uri, "/..")) goto out403; if ((ftype = strrchr(uri, '.'))) ftype++; mtype = ftype2mtype(ftype, wkspace, sizeof(wkspace)); /* Cap maximum length */ len = strlen(uri) + strlen(ast_config_AST_DATA_DIR) + strlen("/static-http/") + 5; if (len > 1024) goto out403; path = alloca(len); sprintf(path, "%s/static-http/%s", ast_config_AST_DATA_DIR, uri); if (stat(path, &st)) goto out404; if (S_ISDIR(st.st_mode)) goto out404; fd = open(path, O_RDONLY); if (fd < 0) goto out403; len = st.st_size + strlen(mtype) + 40; blob = malloc(len); if (blob) { c = blob; sprintf(c, "Content-type: %s\r\n\r\n", mtype); c += strlen(c); *contentlength = read(fd, c, st.st_size); if (*contentlength < 0) { close(fd); free(blob); goto out403; } } close(fd); return blob; out404: *status = 404; *title = strdup("Not Found"); return ast_http_error(404, "Not Found", NULL, "The requested URL was not found on this server."); out403: *status = 403; *title = strdup("Access Denied"); return ast_http_error(403, "Access Denied", NULL, "You do not have permission to access the requested URL."); }
static struct ast_str *http_post_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *vars, struct ast_variable *headers, int *status, char **title, int *contentlength) { struct ast_variable *var; unsigned long ident = 0; FILE *f; int content_len = 0; struct ast_str *post_dir; GMimeMessage *message; int message_count = 0; char * boundary_marker = NULL; if (!urih) { return ast_http_error((*status = 400), (*title = ast_strdup("Missing URI handle")), NULL, "There was an error parsing the request"); } for (var = vars; var; var = var->next) { if (strcasecmp(var->name, "mansession_id")) { continue; } if (sscanf(var->value, "%30lx", &ident) != 1) { return ast_http_error((*status = 400), (*title = ast_strdup("Bad Request")), NULL, "The was an error parsing the request."); } if (!astman_verify_session_writepermissions(ident, EVENT_FLAG_CONFIG)) { return ast_http_error((*status = 401), (*title = ast_strdup("Unauthorized")), NULL, "You are not authorized to make this request."); } break; } if (!var) { return ast_http_error((*status = 401), (*title = ast_strdup("Unauthorized")), NULL, "You are not authorized to make this request."); } if (!(f = tmpfile())) { ast_log(LOG_ERROR, "Could not create temp file.\n"); return NULL; } for (var = headers; var; var = var->next) { fprintf(f, "%s: %s\r\n", var->name, var->value); if (!strcasecmp(var->name, "Content-Length")) { if ((sscanf(var->value, "%30u", &content_len)) != 1) { ast_log(LOG_ERROR, "Invalid Content-Length in POST request!\n"); fclose(f); return NULL; } ast_debug(1, "Got a Content-Length of %d\n", content_len); } else if (!strcasecmp(var->name, "Content-Type")) { boundary_marker = strstr(var->value, "boundary="); if (boundary_marker) { boundary_marker += strlen("boundary="); } } } fprintf(f, "\r\n"); if (0 > readmimefile(ser->f, f, boundary_marker, content_len)) { if (option_debug) { ast_log(LOG_DEBUG, "Cannot find boundary marker in POST request.\n"); } fclose(f); return NULL; } if (fseek(f, SEEK_SET, 0)) { ast_log(LOG_ERROR, "Failed to seek temp file back to beginning.\n"); fclose(f); return NULL; } post_dir = urih->data; message = parse_message(f); /* Takes ownership and will close f */ if (!message) { ast_log(LOG_ERROR, "Error parsing MIME data\n"); return ast_http_error((*status = 400), (*title = ast_strdup("Bad Request")), NULL, "The was an error parsing the request."); } if (!(message_count = process_message(message, ast_str_buffer(post_dir)))) { ast_log(LOG_ERROR, "Invalid MIME data, found no parts!\n"); g_object_unref(message); return ast_http_error((*status = 400), (*title = ast_strdup("Bad Request")), NULL, "The was an error parsing the request."); } g_object_unref(message); return ast_http_error((*status = 200), (*title = ast_strdup("OK")), NULL, "File successfully uploaded."); }
/*! * \internal * \brief ARI HTTP handler. * * This handler takes the HTTP request and turns it into the appropriate * RESTful request (conversion to JSON, routing, etc.) * * \param ser TCP session. * \param urih URI handler. * \param uri URI requested. * \param method HTTP method. * \param get_params HTTP \c GET params. * \param headers HTTP headers. */ static int ast_ari_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers) { RAII_VAR(struct ast_ari_conf *, conf, NULL, ao2_cleanup); RAII_VAR(struct ast_str *, response_body, ast_str_create(256), ast_free); RAII_VAR(struct ast_ari_conf_user *, user, NULL, ao2_cleanup); struct ast_ari_response response = {}; RAII_VAR(struct ast_variable *, post_vars, NULL, ast_variables_destroy); if (!response_body) { ast_http_request_close_on_completion(ser); ast_http_error(ser, 500, "Server Error", "Out of memory"); return 0; } response.headers = ast_str_create(40); if (!response.headers) { ast_http_request_close_on_completion(ser); ast_http_error(ser, 500, "Server Error", "Out of memory"); return 0; } conf = ast_ari_config_get(); if (!conf || !conf->general) { ast_free(response.headers); ast_http_request_close_on_completion(ser); ast_http_error(ser, 500, "Server Error", "URI handler config missing"); return 0; } process_cors_request(headers, &response); /* Process form data from a POST. It could be mixed with query * parameters, which seems a bit odd. But it's allowed, so that's okay * with us. */ post_vars = ast_http_get_post_vars(ser, headers); if (!post_vars) { switch (errno) { case EFBIG: ast_ari_response_error(&response, 413, "Request Entity Too Large", "Request body too large"); goto request_failed; case ENOMEM: ast_http_request_close_on_completion(ser); ast_ari_response_error(&response, 500, "Internal Server Error", "Out of memory"); goto request_failed; case EIO: ast_ari_response_error(&response, 400, "Bad Request", "Error parsing request body"); goto request_failed; } } if (get_params == NULL) { get_params = post_vars; } else if (get_params && post_vars) { /* Has both post_vars and get_params */ struct ast_variable *last_var = post_vars; while (last_var->next) { last_var = last_var->next; } /* The duped get_params will get freed when post_vars gets * ast_variables_destroyed. */ last_var->next = ast_variables_dup(get_params); get_params = post_vars; } user = authenticate_user(get_params, headers); if (response.response_code > 0) { /* POST parameter processing error. Do nothing. */ } else if (!user) { /* Per RFC 2617, section 1.2: The 401 (Unauthorized) response * message is used by an origin server to challenge the * authorization of a user agent. This response MUST include a * WWW-Authenticate header field containing at least one * challenge applicable to the requested resource. */ ast_ari_response_error(&response, 401, "Unauthorized", "Authentication required"); /* Section 1.2: * realm = "realm" "=" realm-value * realm-value = quoted-string * Section 2: * challenge = "Basic" realm */ ast_str_append(&response.headers, 0, "WWW-Authenticate: Basic realm=\"%s\"\r\n", conf->general->auth_realm); } else if (!ast_fully_booted) { ast_http_request_close_on_completion(ser); ast_ari_response_error(&response, 503, "Service Unavailable", "Asterisk not booted"); } else if (user->read_only && method != AST_HTTP_GET && method != AST_HTTP_OPTIONS) { ast_ari_response_error(&response, 403, "Forbidden", "Write access denied"); } else if (ast_ends_with(uri, "/")) { remove_trailing_slash(uri, &response); } else if (ast_begins_with(uri, "api-docs/")) { /* Serving up API docs */ if (method != AST_HTTP_GET) { ast_ari_response_error(&response, 405, "Method Not Allowed", "Unsupported method"); } else { /* Skip the api-docs prefix */ ast_ari_get_docs(strchr(uri, '/') + 1, headers, &response); } } else { /* Other RESTful resources */ ast_ari_invoke(ser, uri, method, get_params, headers, &response); } if (response.no_response) { /* The handler indicates no further response is necessary. * Probably because it already handled it */ ast_free(response.headers); return 0; } request_failed: /* If you explicitly want to have no content, set message to * ast_json_null(). */ ast_assert(response.message != NULL); ast_assert(response.response_code > 0); /* response.message could be NULL, in which case the empty response_body * is correct */ if (response.message && !ast_json_is_null(response.message)) { ast_str_append(&response.headers, 0, "Content-type: application/json\r\n"); if (ast_json_dump_str_format(response.message, &response_body, conf->general->format) != 0) { /* Error encoding response */ response.response_code = 500; response.response_text = "Internal Server Error"; ast_str_set(&response_body, 0, "%s", ""); ast_str_set(&response.headers, 0, "%s", ""); } } ast_debug(3, "Examining ARI response:\n%d %s\n%s\n%s\n", response.response_code, response.response_text, ast_str_buffer(response.headers), ast_str_buffer(response_body)); ast_http_send(ser, method, response.response_code, response.response_text, response.headers, response_body, 0, 0); /* ast_http_send takes ownership, so we don't have to free them */ response_body = NULL; ast_json_unref(response.message); return 0; }
static int http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers) { char file_name[64] = "/tmp/test-media-cache-XXXXXX"; struct ast_str *http_header = ast_str_create(128); struct ast_str *cache_control = ast_str_create(128); int fd = -1; int unmodified = 0; int send_file = options.send_file && method == AST_HTTP_GET; if (!http_header) { goto error; } if (send_file) { char buf[1024]; fd = mkstemp(file_name); if (fd == -1) { ast_log(LOG_ERROR, "Unable to open temp file for testing: %s (%d)", strerror(errno), errno); goto error; } memset(buf, 1, sizeof(buf)); if (write(fd, buf, sizeof(buf)) != sizeof(buf)) { ast_log(LOG_ERROR, "Failed to write expected number of bytes to pipe\n"); close(fd); goto error; } close(fd); fd = open(file_name, 0); if (fd == -1) { ast_log(LOG_ERROR, "Unable to open temp file for testing: %s (%d)", strerror(errno), errno); goto error; } } if (options.cache_control.maxage) { SET_OR_APPEND_CACHE_CONTROL(cache_control); ast_str_append(&cache_control, 0, "max-age=%d", options.cache_control.maxage); } if (options.cache_control.s_maxage) { SET_OR_APPEND_CACHE_CONTROL(cache_control); ast_str_append(&cache_control, 0, "s-maxage=%d", options.cache_control.s_maxage); } if (options.cache_control.no_cache) { SET_OR_APPEND_CACHE_CONTROL(cache_control); ast_str_append(&cache_control, 0, "%s", "no-cache"); } if (options.cache_control.must_revalidate) { SET_OR_APPEND_CACHE_CONTROL(cache_control); ast_str_append(&cache_control, 0, "%s", "must-revalidate"); } if (ast_str_strlen(cache_control)) { ast_str_append(&http_header, 0, "%s\r\n", ast_str_buffer(cache_control)); } if (options.expires.tv_sec) { struct ast_tm now_time; char tmbuf[64]; ast_localtime(&options.expires, &now_time, NULL); ast_strftime(tmbuf, sizeof(tmbuf), "%a, %d %b %Y %T %z", &now_time); ast_str_append(&http_header, 0, "Expires: %s\r\n", tmbuf); } if (!ast_strlen_zero(options.etag)) { struct ast_variable *v; ast_str_append(&http_header, 0, "ETag: %s\r\n", options.etag); for (v = headers; v; v = v->next) { if (!strcasecmp(v->name, "If-None-Match") && !strcasecmp(v->value, options.etag)) { unmodified = 1; break; } } } if (!unmodified) { ast_http_send(ser, method, options.status_code, options.status_text, http_header, NULL, send_file ? fd : 0, 1); } else { ast_http_send(ser, method, 304, "Not Modified", http_header, NULL, 0, 1); } if (send_file) { close(fd); unlink(file_name); } ast_free(cache_control); return 0; error: ast_free(http_header); ast_free(cache_control); ast_http_request_close_on_completion(ser); ast_http_error(ser, 418, "I'm a Teapot", "Please don't ask me to brew coffee."); return 0; }
static int http_post_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_vars, struct ast_variable *headers) { struct ast_variable *var, *cookies; unsigned long ident = 0; FILE *f; int content_len = 0; struct ast_str *post_dir; GMimeMessage *message; int message_count = 0; char * boundary_marker = NULL; if (method != AST_HTTP_POST) { ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method"); return -1; } if (!astman_is_authed(ast_http_manid_from_vars(headers))) { ast_http_error(ser, 403, "Access Denied", "Sorry, I cannot let you do that, Dave."); return -1; } if (!urih) { ast_http_error(ser, 400, "Missing URI handle", "There was an error parsing the request"); return -1; } cookies = ast_http_get_cookies(headers); for (var = cookies; var; var = var->next) { if (!strcasecmp(var->name, "mansession_id")) { sscanf(var->value, "%30lx", &ident); break; } } if (cookies) { ast_variables_destroy(cookies); } if (ident == 0) { ast_http_error(ser, 401, "Unauthorized", "You are not authorized to make this request."); return -1; } if (!astman_verify_session_writepermissions(ident, EVENT_FLAG_CONFIG)) { ast_http_error(ser, 401, "Unauthorized", "You are not authorized to make this request."); return -1; } if (!(f = tmpfile())) { ast_log(LOG_ERROR, "Could not create temp file.\n"); ast_http_error(ser, 500, "Internal server error", "Could not create temp file."); return -1; } for (var = headers; var; var = var->next) { fprintf(f, "%s: %s\r\n", var->name, var->value); if (!strcasecmp(var->name, "Content-Length")) { if ((sscanf(var->value, "%30u", &content_len)) != 1) { ast_log(LOG_ERROR, "Invalid Content-Length in POST request!\n"); fclose(f); ast_http_error(ser, 500, "Internal server error", "Invalid Content-Length in POST request!"); return -1; } ast_debug(1, "Got a Content-Length of %d\n", content_len); } else if (!strcasecmp(var->name, "Content-Type")) { boundary_marker = strstr(var->value, "boundary="); if (boundary_marker) { boundary_marker += strlen("boundary="); } } } fprintf(f, "\r\n"); if (0 > readmimefile(ser->f, f, boundary_marker, content_len)) { if (option_debug) { ast_log(LOG_DEBUG, "Cannot find boundary marker in POST request.\n"); } fclose(f); return -1; } if (fseek(f, SEEK_SET, 0)) { ast_log(LOG_ERROR, "Failed to seek temp file back to beginning.\n"); fclose(f); ast_http_error(ser, 500, "Internal server error", "Failed to seek temp file back to beginning."); return -1; } post_dir = urih->data; message = parse_message(f); /* Takes ownership and will close f */ if (!message) { ast_log(LOG_ERROR, "Error parsing MIME data\n"); ast_http_error(ser, 400, "Bad Request", "The was an error parsing the request."); return -1; } if (!(message_count = process_message(message, ast_str_buffer(post_dir)))) { ast_log(LOG_ERROR, "Invalid MIME data, found no parts!\n"); g_object_unref(message); ast_http_error(ser, 400, "Bad Request", "The was an error parsing the request."); return -1; } g_object_unref(message); ast_http_error(ser, 200, "OK", "File successfully uploaded."); return 0; }
static void *ast_httpd_helper_thread(void *data) { char buf[4096]; char cookie[4096]; char timebuf[256]; struct ast_http_server_instance *ser = data; struct ast_variable *var, *prev=NULL, *vars=NULL; char *uri, *c, *title=NULL; char *vname, *vval; int status = 200, contentlength = 0; time_t t; if (fgets(buf, sizeof(buf), ser->f)) { /* Skip method */ uri = buf; while(*uri && (*uri > 32)) uri++; if (*uri) { *uri = '\0'; uri++; } /* Skip white space */ while (*uri && (*uri < 33)) uri++; if (*uri) { c = uri; while (*c && (*c > 32)) c++; if (*c) { *c = '\0'; } } while (fgets(cookie, sizeof(cookie), ser->f)) { /* Trim trailing characters */ while(!ast_strlen_zero(cookie) && (cookie[strlen(cookie) - 1] < 33)) { cookie[strlen(cookie) - 1] = '\0'; } if (ast_strlen_zero(cookie)) break; if (!strncasecmp(cookie, "Cookie: ", 8)) { vname = cookie + 8; vval = strchr(vname, '='); if (vval) { /* Ditch the = and the quotes */ *vval = '\0'; vval++; if (*vval) vval++; if (strlen(vval)) vval[strlen(vval) - 1] = '\0'; var = ast_variable_new(vname, vval); if (var) { if (prev) prev->next = var; else vars = var; prev = var; } } } } if (*uri) { if (!strcasecmp(buf, "get")) c = handle_uri(&ser->requestor, uri, &status, &title, &contentlength, &vars); else c = ast_http_error(501, "Not Implemented", NULL, "Attempt to use unimplemented / unsupported method");\ } else c = ast_http_error(400, "Bad Request", NULL, "Invalid Request"); /* If they aren't mopped up already, clean up the cookies */ if (vars) ast_variables_destroy(vars); if (!c) c = ast_http_error(500, "Internal Error", NULL, "Internal Server Error"); if (c) { time(&t); strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&t)); ast_cli(ser->fd, "HTTP/1.1 %d %s\r\n", status, title ? title : "OK"); ast_cli(ser->fd, "Server: Asterisk\r\n"); ast_cli(ser->fd, "Date: %s\r\n", timebuf); ast_cli(ser->fd, "Connection: close\r\n"); if (contentlength) { char *tmp; tmp = strstr(c, "\r\n\r\n"); if (tmp) { ast_cli(ser->fd, "Content-length: %d\r\n", contentlength); write(ser->fd, c, (tmp + 4 - c)); write(ser->fd, tmp + 4, contentlength); } } else ast_cli(ser->fd, "%s", c); free(c); } if (title) free(title); } fclose(ser->f); free(ser); return NULL; }