[svn-commits] rmudgett: branch rmudgett/http_persistent r417545 - in /team/rmudgett/http_pe...
SVN commits to the Digium repositories
svn-commits at lists.digium.com
Fri Jun 27 14:49:47 CDT 2014
Author: rmudgett
Date: Fri Jun 27 14:49:40 2014
New Revision: 417545
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=417545
Log:
* Made keep track of HTTP request body reading so it could be discarded if
it has not been read.
* Made keep connection on non-2xx level response codes.
Modified:
team/rmudgett/http_persistent/include/asterisk/http.h
team/rmudgett/http_persistent/main/http.c
team/rmudgett/http_persistent/main/manager.c
team/rmudgett/http_persistent/res/res_http_post.c
team/rmudgett/http_persistent/res/res_http_websocket.c
team/rmudgett/http_persistent/res/res_phoneprov.c
Modified: team/rmudgett/http_persistent/include/asterisk/http.h
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/http_persistent/include/asterisk/http.h?view=diff&rev=417545&r1=417544&r2=417545
==============================================================================
--- team/rmudgett/http_persistent/include/asterisk/http.h (original)
+++ team/rmudgett/http_persistent/include/asterisk/http.h Fri Jun 27 14:49:40 2014
@@ -193,7 +193,7 @@
*/
void ast_http_send(struct ast_tcptls_session_instance *ser, enum ast_http_method method,
int status_code, const char *status_title, struct ast_str *http_header,
- struct ast_str *out, const int fd, unsigned int static_content);
+ struct ast_str *out, int fd, unsigned int static_content);
/*! \brief Send http "401 Unauthorized" response and close socket */
void ast_http_auth(struct ast_tcptls_session_instance *ser, const char *realm, const unsigned long nonce, const unsigned long opaque, int stale, const char *text);
@@ -209,6 +209,27 @@
*/
void ast_http_prefix(char *buf, int len);
+/*!
+ * \brief Update the body read success status.
+ * \since 12.4.0
+ *
+ * \param ser HTTP TCP/TLS session object.
+ * \param read_success TRUE if body was read successfully.
+ *
+ * \return Nothing
+ */
+void ast_http_body_read_status(struct ast_tcptls_session_instance *ser, int read_success);
+
+/*!
+ * \brief Read and discard any unread HTTP request body.
+ * \since 12.4.0
+ *
+ * \param ser HTTP TCP/TLS session object.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+int ast_http_body_discard(struct ast_tcptls_session_instance *ser);
/*!
* \brief Get post variables from client Request Entity-Body, if content type is application/x-www-form-urlencoded.
Modified: team/rmudgett/http_persistent/main/http.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/http_persistent/main/http.c?view=diff&rev=417545&r1=417544&r2=417545
==============================================================================
--- team/rmudgett/http_persistent/main/http.c (original)
+++ team/rmudgett/http_persistent/main/http.c Fri Jun 27 14:49:40 2014
@@ -237,7 +237,7 @@
if (method != AST_HTTP_GET && method != AST_HTTP_HEAD) {
ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method");
- return -1;
+ return 0;
}
/* Yuck. I'm not really sold on this, but if you don't deliver static content it makes your configuration
@@ -310,7 +310,7 @@
if (!http_header) {
ast_http_error(ser, 500, "Server Error", "Out of memory");
close(fd);
- return -1;
+ return 0;
}
ast_str_set(&http_header, 0, "Content-type: %s\r\n"
@@ -331,11 +331,11 @@
out404:
ast_http_error(ser, 404, "Not Found", "The requested URL was not found on this server.");
- return -1;
+ return 0;
out403:
ast_http_error(ser, 403, "Access Denied", "You do not have permission to access the requested URL.");
- return -1;
+ return 0;
}
static int httpstatus_callback(struct ast_tcptls_session_instance *ser,
@@ -348,13 +348,13 @@
if (method != AST_HTTP_GET && method != AST_HTTP_HEAD) {
ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method");
- return -1;
+ return 0;
}
out = ast_str_create(512);
if (!out) {
ast_http_error(ser, 500, "Server Error", "Out of memory");
- return -1;
+ return 0;
}
ast_str_append(&out, 0,
@@ -409,17 +409,19 @@
/*! HTTP tcptls worker_fn private data. */
struct http_worker_private_data {
- /*! TRUE if the HTTP request wants the connection closed when completed. */
- unsigned int wants_closed:1;
+ /*! Body length or -1 if chunked. Valid if has_body is TRUE. */
+ int body_length;
/*! TRUE if the HTTP request has a body. */
unsigned int has_body:1;
/*! TRUE if the HTTP request body has been read. */
unsigned int body_read:1;
+ /*! TRUE if the HTTP request must close when completed. */
+ unsigned int close_on_completion:1;
};
void ast_http_send(struct ast_tcptls_session_instance *ser,
enum ast_http_method method, int status_code, const char *status_title,
- struct ast_str *http_header, struct ast_str *out, const int fd,
+ struct ast_str *http_header, struct ast_str *out, int fd,
unsigned int static_content)
{
struct timeval now = ast_tvnow();
@@ -435,25 +437,24 @@
return;
}
-/* BUGBUG Relax close on non 2xx status codes? */
/*
- * XXX We may be able to relax the closing of the connection
- * if the status_code is other than 2xx because we are keeping
- * track of whether the request body is read or not. The URI
- * handler functions would not need to return -1 for those cases.
+ * We shouldn't be sending non-final status codes to this
+ * function because we may close the connection before
+ * returning.
*/
- if (session_keep_alive <= 0 || status_code < 200 || 299 < status_code) {
+ ast_assert(200 <= status_code);
+
+ if (session_keep_alive <= 0) {
close_connection = 1;
} else {
struct http_worker_private_data *request;
request = ser->private_data;
- if (!request
- || request->wants_closed
- || (request->has_body && !request->body_read)) {
+ if (!request || request->close_on_completion) {
close_connection = 1;
} else {
- close_connection = 0;
+ ast_http_body_discard(ser);
+ close_connection = request->close_on_completion;
}
}
@@ -476,16 +477,16 @@
"Date: %s\r\n"
"%s"
"%s"
+ "%s"
"Content-Length: %d\r\n"
- "%s"
"\r\n",
status_code, status_title ? status_title : "OK",
ast_get_version(),
timebuf,
close_connection ? "Connection: close\r\n" : "",
static_content ? "" : "Cache-Control: no-cache, no-store\r\n",
- content_length,
- http_header ? ast_str_buffer(http_header) : ""
+ http_header ? ast_str_buffer(http_header) : "",
+ content_length
);
/* send content */
@@ -515,9 +516,11 @@
ast_free(out);
if (close_connection) {
+ ast_debug(1, "HTTP closing session. status_code:%d\n", status_code);
ast_log(LOG_NOTICE, "BUGBUG HTTP closing session. status_code:%d\n", status_code);
ast_tcptls_close_session_file(ser);
} else {
+ ast_debug(1, "HTTP keeping session open. status_code:%d\n", status_code);
ast_log(LOG_NOTICE, "BUGBUG HTTP keeping session open. status_code:%d\n", status_code);
}
}
@@ -533,6 +536,7 @@
ast_free(http_headers);
ast_free(out);
if (ser && ser->f) {
+ ast_debug(1, "HTTP closing session. Auth OOM\n");
ast_log(LOG_NOTICE, "BUGBUG HTTP closing session. Auth OOM\n");
ast_tcptls_close_session_file(ser);
}
@@ -571,6 +575,7 @@
ast_free(http_headers);
ast_free(out);
if (ser && ser->f) {
+ ast_debug(1, "HTTP closing session. error OOM\n");
ast_log(LOG_NOTICE, "BUGBUG HTTP closing session. error OOM\n");
ast_tcptls_close_session_file(ser);
}
@@ -709,29 +714,35 @@
* \brief Returns the value of the Content-Length header.
*
* \param headers HTTP headers.
- * \return Value of the Content-Length header.
- * \return 0 if header is not present, or is invalid.
+ *
+ * \retval length Value of the Content-Length header.
+ * \retval 0 if header is not present.
+ * \retval -1 if header is invalid.
*/
static int get_content_length(struct ast_variable *headers)
{
const char *content_length = get_header(headers, "Content-Length");
+ int length;
if (!content_length) {
/* Missing content length; assume zero */
return 0;
}
- /* atoi() will return 0 for invalid inputs, which is good enough for
- * the HTTP parsing. */
- return atoi(content_length);
+ length = 0;
+ if (sscanf(content_length, "%30d", &length) != 1) {
+ /* Invalid Content-Length value */
+ length = -1;
+ }
+ return length;
}
/*!
* \brief Returns the value of the Transfer-Encoding header.
*
* \param headers HTTP headers.
- * \return Value of the Transfer-Encoding header.
- * \return 0 if header is not present, or is invalid.
+ * \retval Value of the Transfer-Encoding header.
+ * \retval 0 if header is not present, or is invalid.
*/
static const char *get_transfer_encoding(struct ast_variable *headers)
{
@@ -791,31 +802,203 @@
/*!
* \internal
- * \brief Determine if the HTTP request has a body.
+ * \brief Determine if the HTTP peer wants the connection closed.
*
* \param headers List of HTTP headers
*
- * \return TRUE if the request has a body.
+ * \retval 0 keep connection open.
+ * \retval -1 close connection.
*/
-static int http_has_request_body(struct ast_variable *headers)
-{
+static int http_check_connection_close(struct ast_variable *headers)
+{
+ const char *connection = get_header(headers, "Connection");
+ int close_connection = 0;
+
+ if (connection && !strcasecmp(connection, "close")) {
+ close_connection = -1;
+ }
+ return close_connection;
+}
+
+/*!
+ * \internal
+ * \brief Setup the HTTP request tracking information.
+ *
+ * \param ser HTTP TCP/TLS session object.
+ * \param headers List of HTTP headers.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+static int http_request_tracking_setup(struct ast_tcptls_session_instance *ser, struct ast_variable *headers)
+{
+ struct http_worker_private_data *request = ser->private_data;
const char *transfer_encoding;
+ request->has_body = 0;
+ request->body_read = 0;
+ request->close_on_completion = http_check_connection_close(headers) ? 1 : 0;
+
transfer_encoding = get_transfer_encoding(headers);
- if (ast_strlen_zero(transfer_encoding)
- || strcasecmp(transfer_encoding, "chunked") != 0) {
- return 0 < get_content_length(headers);
- }
-
- /* Has a chunked body. */
- return 1;
+ if (transfer_encoding && !strcasecmp(transfer_encoding, "chunked")) {
+ request->body_length = -1;
+ request->has_body = 1;
+ return 0;
+ }
+
+ request->body_length = get_content_length(headers);
+ if (0 < request->body_length) {
+ request->has_body = 1;
+ } else if (request->body_length < 0) {
+ /* Invalid Content-Length */
+ request->close_on_completion = 1;
+ ast_http_error(ser, 400, "Bad Request", "Invalid Content-Length in request!");
+ return -1;
+ }
+ return 0;
+}
+
+void ast_http_body_read_status(struct ast_tcptls_session_instance *ser, int read_success)
+{
+ struct http_worker_private_data *request;
+
+ request = ser->private_data;
+ if (!request->has_body || request->body_read) {
+ /* No body to read. */
+ return;
+ }
+ request->body_read = 1;
+ if (!read_success) {
+ request->close_on_completion = 1;
+ }
+}
+
+int ast_http_body_discard(struct ast_tcptls_session_instance *ser)
+{
+ struct http_worker_private_data *request;
+ int length;
+ int res;
+ char buf[4096];/* Discard buffer */
+
+ request = ser->private_data;
+ if (!request->has_body || request->body_read) {
+ /* No body to read or it has already been read. */
+ return 0;
+ }
+ request->body_read = 1;
+
+ ast_debug(1, "HTTP discarding unused request body\n");
+ ast_log(LOG_NOTICE, "BUGBUG HTTP discarding unused request body\n");
+
+ ast_assert(request->body_length != 0);
+ if (0 < request->body_length) {
+ length = request->body_length;
+
+ /* Stay in fread until get all the expected data or timeout. */
+ while (sizeof(buf) < length) {
+ res = fread(buf, sizeof(buf), 1, ser->f);
+ if (res < 1) {
+ ast_log(LOG_WARNING,
+ "Short HTTP request body (Wanted %d of remaining %d)\n",
+ (int) sizeof(buf), length);
+ request->close_on_completion = 1;
+ return -1;
+ }
+ length -= sizeof(buf);
+ }
+ res = fread(buf, length, 1, ser->f);
+ if (res < 1) {
+ ast_log(LOG_WARNING,
+ "Short HTTP request body (Wanted %d of remaining %d)\n",
+ length, length);
+ request->close_on_completion = 1;
+ return -1;
+ }
+ return 0;
+ }
+
+ /* parse chunked-body */
+ for (;;) {
+ /* get the line of hexadecimal giving chunk-size w/ optional chunk-extension */
+ if (!fgets(buf, sizeof(buf), ser->f)) {
+ ast_log(LOG_WARNING,
+ "Short HTTP read of chunked header\n");
+ request->close_on_completion = 1;
+ return -1;
+ }
+ length = chunked_atoh(buf, sizeof(buf));
+ if (length < 0) {
+ ast_log(LOG_WARNING, "Invalid HTTP chunk size\n");
+ request->close_on_completion = 1;
+ return -1;
+ }
+ if (length == 0) {
+ /* parsed last-chunk */
+ break;
+ }
+
+ /* Stay in fread until get all the expected chunk-data or timeout. */
+ while (sizeof(buf) < length) {
+ res = fread(buf, sizeof(buf), 1, ser->f);
+ if (res < 1) {
+ ast_log(LOG_WARNING,
+ "Short HTTP request chunk-data (Wanted %d of remaining %d)\n",
+ (int) sizeof(buf), length);
+ request->close_on_completion = 1;
+ return -1;
+ }
+ length -= sizeof(buf);
+ }
+ res = fread(buf, length, 1, ser->f);
+ if (res < 1) {
+ ast_log(LOG_WARNING,
+ "Short HTTP request chunk-data (Wanted %d of remaining %d)\n",
+ length, length);
+ request->close_on_completion = 1;
+ return -1;
+ }
+
+ /* Stay in fread until get the expected CRLF or timeout. */
+ res = fread(buf, 2, 1, ser->f);
+ if (res < 1) {
+ ast_log(LOG_WARNING,
+ "Short HTTP chunk sync read (Wanted 2)\n");
+ request->close_on_completion = 1;
+ return -1;
+ }
+ if (buf[0] != 0x0D || buf[1] != 0x0A) {
+ ast_log(LOG_WARNING,
+ "Post HTTP chunk sync bytes wrong (%d, %d)\n",
+ buf[0], buf[1]);
+ request->close_on_completion = 1;
+ return -1;
+ }
+ }
+
+ /* Read and discard any trailer entity-header lines. */
+ for (;;) {
+ if (!fgets(buf, sizeof(buf), ser->f)) {
+ ast_log(LOG_WARNING,
+ "Short HTTP read of chunked trailer header\n");
+ request->close_on_completion = 1;
+ return -1;
+ }
+
+ /* Trim trailing whitespace */
+ ast_trim_blanks(buf);
+ if (ast_strlen_zero(buf)) {
+ /* A blank line ends the chunked-body */
+ break;
+ }
+ }
+ return 0;
}
/*!
* \brief Returns the contents (body) of the HTTP request
*
* \param return_length ptr to int that returns content length
- * \param aser HTTP TCP/TLS session object
+ * \param ser HTTP TCP/TLS session object
* \param headers List of HTTP headers
* \return ptr to content (zero terminated) or NULL on failure
* \note Since returned ptr is malloc'd, it should be free'd by caller
@@ -824,9 +1007,8 @@
struct ast_tcptls_session_instance *ser, struct ast_variable *headers)
{
struct http_worker_private_data *request;
- const char *transfer_encoding;
int res;
- int content_length = 0;
+ int content_length;
int chunk_length;
char header_line[4096];
int bufsize = 250;
@@ -835,27 +1017,36 @@
#define MAX_CONTENT_LENGTH 4096
request = ser->private_data;
- transfer_encoding = get_transfer_encoding(headers);
-
- if (ast_strlen_zero(transfer_encoding) ||
- strcasecmp(transfer_encoding, "chunked") != 0) {
+ if (!request->has_body) {
+ /* no content - not an error */
+ return NULL;
+ }
+ if (request->body_read) {
+ /* Already read the body. Cannot read again. Assume no content. */
+ ast_assert(0);
+ return NULL;
+ }
+ request->body_read = 1;
+
+ ast_debug(1, "HTTP consuming request body\n");
+ ast_log(LOG_NOTICE, "BUGBUG HTTP consuming request body\n");
+
+ ast_assert(request->body_length != 0);
+ if (0 < request->body_length) {
/* handle regular non-chunked content */
- content_length = get_content_length(headers);
- if (content_length <= 0) {
- /* no content - not an error */
- request->body_read = 1;
- return NULL;
- }
+ content_length = request->body_length;
if (content_length > MAX_CONTENT_LENGTH) {
ast_log(LOG_WARNING,
"Excessively long HTTP content. (%d > %d)\n",
content_length, MAX_CONTENT_LENGTH);
+ request->close_on_completion = 1;
errno = EFBIG;
return NULL;
}
buf = ast_malloc(content_length + 1);
if (!buf) {
/* Malloc sets ENOMEM */
+ request->close_on_completion = 1;
return NULL;
}
@@ -866,12 +1057,12 @@
* is good. Treat either one as I/O error */
ast_log(LOG_WARNING, "Short HTTP request body (Wanted %d)\n",
content_length);
+ request->close_on_completion = 1;
errno = EIO;
ast_free(buf);
return NULL;
}
- request->body_read = 1;
buf[content_length] = 0;
*return_length = content_length;
return buf;
@@ -880,15 +1071,18 @@
/* pre-allocate buffer */
buf = ast_malloc(bufsize);
if (!buf) {
+ request->close_on_completion = 1;
return NULL;
}
/* parse chunked-body */
+ content_length = 0;
for (;;) {
/* get the line of hexadecimal giving chunk-size w/ optional chunk-extension */
if (!fgets(header_line, sizeof(header_line), ser->f)) {
ast_log(LOG_WARNING,
"Short HTTP read of chunked header\n");
+ request->close_on_completion = 1;
errno = EIO;
ast_free(buf);
return NULL;
@@ -897,6 +1091,7 @@
chunk_length = chunked_atoh(header_line, sizeof(header_line));
if (chunk_length < 0) {
ast_log(LOG_WARNING, "Invalid HTTP chunk size\n");
+ request->close_on_completion = 1;
errno = EIO;
ast_free(buf);
return NULL;
@@ -909,6 +1104,7 @@
ast_log(LOG_WARNING,
"Excessively long HTTP chunk. (%d + %d > %d)\n",
content_length, chunk_length, MAX_CONTENT_LENGTH);
+ request->close_on_completion = 1;
errno = EFBIG;
ast_free(buf);
return NULL;
@@ -925,6 +1121,7 @@
new_buf = ast_realloc(buf, bufsize);
if (!new_buf) {
+ request->close_on_completion = 1;
ast_free(buf);
return NULL;
}
@@ -936,6 +1133,7 @@
if (res < 1) {
ast_log(LOG_WARNING, "Short HTTP chunk read (Wanted %d)\n",
chunk_length);
+ request->close_on_completion = 1;
errno = EIO;
ast_free(buf);
return NULL;
@@ -948,6 +1146,7 @@
if (res < 1) {
ast_log(LOG_WARNING,
"Short HTTP chunk sync read (Wanted 2)\n");
+ request->close_on_completion = 1;
errno = EIO;
ast_free(buf);
return NULL;
@@ -956,6 +1155,7 @@
ast_log(LOG_WARNING,
"Post HTTP chunk sync bytes wrong (%d, %d)\n",
header_line[0], header_line[1]);
+ request->close_on_completion = 1;
errno = EIO;
ast_free(buf);
return NULL;
@@ -974,6 +1174,7 @@
if (!fgets(header_line, sizeof(header_line), ser->f)) {
ast_log(LOG_WARNING,
"Short HTTP read of chunked trailer header\n");
+ request->close_on_completion = 1;
errno = EIO;
ast_free(buf);
return NULL;
@@ -989,7 +1190,6 @@
ast_log(LOG_NOTICE, "BUGBUG Discarding chunked trailer header: '%s'\n", header_line);
}
- request->body_read = 1;
buf[content_length] = 0;
*return_length = content_length;
return buf;
@@ -1086,7 +1286,7 @@
enum ast_http_method method, struct ast_variable *headers)
{
char *c;
- int res = -1;
+ int res = 0;
char *params = uri;
struct ast_http_uri *urih = NULL;
int l;
@@ -1361,17 +1561,6 @@
return NULL;
}
-static int http_check_connection_close(struct ast_variable *headers)
-{
- const char *connection = get_header(headers, "Connection");
- int close_connection = 0;
-
- if (connection && !strcasecmp(connection, "close")) {
- close_connection = -1;
- }
- return close_connection;
-}
-
/*! Limit the number of request headers in case the sender is being ridiculous. */
#define MAX_HTTP_REQUEST_HEADERS 100
@@ -1395,8 +1584,7 @@
/* Initialize the request body flags. */
request = ser->private_data;
- request->has_body = 1;/* For safety, assume the request has a body. */
- request->body_read = 0;
+ request->close_on_completion = 1;/* Assume close in case request fails early */
/* Get method */
method = ast_skip_blanks(buf);
@@ -1504,14 +1692,12 @@
return -1;
}
- res = http_check_connection_close(headers);
- if (res) {
- request->wants_closed = 1;
- }
- request->has_body = http_has_request_body(headers);
-
- if (handle_uri(ser, uri, http_method, headers)) {
+ if (http_request_tracking_setup(ser, headers)
+ || handle_uri(ser, uri, http_method, headers)
+ || request->close_on_completion) {
res = -1;
+ } else {
+ res = 0;
}
return res;
}
@@ -1533,6 +1719,7 @@
session_limit);
goto done;
}
+ ast_debug(1, "HTTP opening session. Top level\n");
ast_log(LOG_NOTICE, "BUGBUG HTTP opening session. Top level\n");
/*
@@ -1567,6 +1754,9 @@
goto done;
}
+ /* Assume close in case request fails early */
+ ((struct http_worker_private_data *) ser->private_data)->close_on_completion = 1;
+
/* Determine initial HTTP request wait timeout. */
timeout = session_keep_alive;
if (timeout <= 0) {
@@ -1588,8 +1778,8 @@
ch = fgetc(ser->f);
if (ch == EOF || ungetc(ch, ser->f) == EOF) {
/* Between request idle timeout */
- ast_debug(1, "HTTP idle timeout closing session\n");
- ast_log(LOG_NOTICE, "BUGBUG HTTP idle timeout.\n");
+ ast_debug(1, "HTTP idle timeout or peer closed connection.\n");
+ ast_log(LOG_NOTICE, "BUGBUG HTTP idle timeout or peer closed connection.\n");
break;
}
@@ -1610,6 +1800,7 @@
ast_atomic_fetchadd_int(&session_count, -1);
if (ser->f) {
+ ast_debug(1, "HTTP closing session. Top level\n");
ast_log(LOG_NOTICE, "BUGBUG HTTP closing session. Top level\n");
ast_tcptls_close_session_file(ser);
}
Modified: team/rmudgett/http_persistent/main/manager.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/http_persistent/main/manager.c?view=diff&rev=417545&r1=417544&r2=417545
==============================================================================
--- team/rmudgett/http_persistent/main/manager.c (original)
+++ team/rmudgett/http_persistent/main/manager.c Fri Jun 27 14:49:40 2014
@@ -6822,7 +6822,6 @@
struct mansession_session *session = NULL;
uint32_t ident;
int blastaway = 0;
- int res = -1;
struct ast_variable *v;
struct ast_variable *params = get_params;
char template[] = "/tmp/ast-http-XXXXXX"; /* template for temporary file */
@@ -6833,7 +6832,7 @@
if (method != AST_HTTP_GET && method != AST_HTTP_HEAD && method != AST_HTTP_POST) {
ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method");
- return -1;
+ return 0;
}
ident = ast_http_manid_from_vars(headers);
@@ -6846,7 +6845,7 @@
*/
if (!(session = build_mansession(remote_address))) {
ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)\n");
- return -1;
+ return 0;
}
ao2_lock(session);
session->send_events = 0;
@@ -7008,7 +7007,6 @@
ast_http_send(ser, method, 200, NULL, http_header, out, 0, 0);
http_header = NULL;
out = NULL;
- res = 0;
generic_callback_out:
ast_mutex_destroy(&s.lock);
@@ -7028,7 +7026,7 @@
session->f = NULL;
}
- return res;
+ return 0;
}
static int auth_http_callback(struct ast_tcptls_session_instance *ser,
@@ -7053,7 +7051,6 @@
struct ast_http_digest d = { NULL, };
struct ast_manager_user *user = NULL;
int stale = 0;
- int res = -1;
char resp_hash[256]="";
/* Cache for user data */
char u_username[80];
@@ -7064,7 +7061,7 @@
if (method != AST_HTTP_GET && method != AST_HTTP_HEAD && method != AST_HTTP_POST) {
ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method");
- return -1;
+ return 0;
}
/* Find "Authorization: " header */
@@ -7081,7 +7078,7 @@
/* Digest found - parse */
if (ast_string_field_init(&d, 128)) {
ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)\n");
- return -1;
+ return 0;
}
if (ast_parse_digest(v->value, &d, 0, 1)) {
@@ -7109,7 +7106,7 @@
AST_RWLIST_UNLOCK(&users);
ast_log(LOG_NOTICE, "%s failed to pass IP ACL as '%s'\n", ast_sockaddr_stringify_addr(&session->addr), d.username);
ast_http_error(ser, 403, "Permission denied", "Permission denied\n");
- return -1;
+ return 0;
}
/* --- We have auth, so check it */
@@ -7159,7 +7156,7 @@
*/
if (!(session = build_mansession(remote_address))) {
ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)\n");
- return -1;
+ return 0;
}
ao2_lock(session);
@@ -7321,7 +7318,6 @@
ast_http_send(ser, method, 200, NULL, http_header, out, 0, 0);
http_header = NULL;
out = NULL;
- res = 0;
auth_callback_out:
ast_mutex_destroy(&s.lock);
@@ -7347,7 +7343,7 @@
session_destroy(session);
}
ast_string_field_free_memory(&d);
- return res;
+ return 0;
out_401:
if (!nonce) {
@@ -7356,7 +7352,7 @@
ast_http_auth(ser, global_realm, nonce, nonce, stale, NULL);
ast_string_field_free_memory(&d);
- return -1;
+ return 0;
}
static int manager_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)
Modified: team/rmudgett/http_persistent/res/res_http_post.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/http_persistent/res/res_http_post.c?view=diff&rev=417545&r1=417544&r2=417545
==============================================================================
--- team/rmudgett/http_persistent/res/res_http_post.c (original)
+++ team/rmudgett/http_persistent/res/res_http_post.c Fri Jun 27 14:49:40 2014
@@ -323,29 +323,29 @@
if (method != AST_HTTP_POST) {
ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method");
- return -1;
+ return 0;
}
if (!urih) {
ast_http_error(ser, 400, "Missing URI handle", "There was an error parsing the request");
- return -1;
+ return 0;
}
ident = ast_http_manid_from_vars(headers);
if (!ident || !astman_is_authed(ident)) {
ast_http_error(ser, 403, "Access Denied", "Sorry, I cannot let you do that, Dave.");
- return -1;
+ return 0;
}
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;
+ 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 -1;
+ return 0;
}
for (var = headers; var; var = var->next) {
@@ -355,8 +355,8 @@
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_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")) {
@@ -366,21 +366,29 @@
}
}
}
-
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->f, 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 -1;
+ 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 -1;
+ return 0;
}
post_dir = urih->data;
@@ -390,14 +398,14 @@
ast_log(LOG_ERROR, "Error parsing MIME data\n");
ast_http_error(ser, 400, "Bad Request", "There was an error parsing the request.");
- return -1;
+ 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 -1;
+ return 0;
}
g_object_unref(message);
Modified: team/rmudgett/http_persistent/res/res_http_websocket.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/http_persistent/res/res_http_websocket.c?view=diff&rev=417545&r1=417544&r2=417545
==============================================================================
--- team/rmudgett/http_persistent/res/res_http_websocket.c (original)
+++ team/rmudgett/http_persistent/res/res_http_websocket.c Fri Jun 27 14:49:40 2014
@@ -587,6 +587,18 @@
return ao2_callback(server->protocols, OBJ_NOLOCK, NULL, NULL);
}
+static void websocket_bad_request(struct ast_tcptls_session_instance *ser)
+{
+ struct ast_str *http_header = ast_str_create(64);
+
+ if (!http_header) {
+ ast_http_error(ser, 500, "Server Error", "Out of memory");
+ return;
+ }
+ ast_str_set(&http_header, 0, "Sec-WebSocket-Version: 7, 8, 13\r\n");
+ ast_http_send(ser, AST_HTTP_UNKNOWN, 400, "Bad Request", http_header, NULL, 0, 0);
+}
+
int AST_OPTIONAL_API_NAME(ast_websocket_uri_cb)(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 *v;
@@ -601,7 +613,7 @@
/* Upgrade requests are only permitted on GET methods */
if (method != AST_HTTP_GET) {
ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method");
- return -1;
+ return 0;
}
server = urih->data;
@@ -631,7 +643,7 @@
ast_log(LOG_WARNING, "WebSocket connection from '%s' could not be accepted - did not request WebSocket\n",
ast_sockaddr_stringify(&ser->remote_address));
ast_http_error(ser, 426, "Upgrade Required", NULL);
- return -1;
+ return 0;
} else if (ast_strlen_zero(requested_protocols)) {
/* If there's only a single protocol registered, and the
* client doesn't specify what protocol it's using, go ahead
@@ -641,18 +653,16 @@
/* Multiple registered subprotocols; client must specify */
ast_log(LOG_WARNING, "WebSocket connection from '%s' could not be accepted - no protocols requested\n",
ast_sockaddr_stringify(&ser->remote_address));
- fputs("HTTP/1.1 400 Bad Request\r\n"
- "Sec-WebSocket-Version: 7, 8, 13\r\n\r\n", ser->f);
- return -1;
+ websocket_bad_request(ser);
+ return 0;
}
} else if (key1 && key2) {
/* Specification defined in http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76 and
* http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-00 -- not currently supported*/
ast_log(LOG_WARNING, "WebSocket connection from '%s' could not be accepted - unsupported version '00/76' chosen\n",
ast_sockaddr_stringify(&ser->remote_address));
- fputs("HTTP/1.1 400 Bad Request\r\n"
- "Sec-WebSocket-Version: 7, 8, 13\r\n\r\n", ser->f);
- return -1;
+ websocket_bad_request(ser);
+ return 0;
}
/* Iterate through the requested protocols trying to find one that we have a handler for */
@@ -664,9 +674,8 @@
if (!protocol_handler) {
ast_log(LOG_WARNING, "WebSocket connection from '%s' could not be accepted - no protocols out of '%s' supported\n",
ast_sockaddr_stringify(&ser->remote_address), protos);
- fputs("HTTP/1.1 400 Bad Request\r\n"
- "Sec-WebSocket-Version: 7, 8, 13\r\n\r\n", ser->f);
- return -1;
+ websocket_bad_request(ser);
+ return 0;
}
/* Determine how to respond depending on the version */
@@ -680,19 +689,23 @@
combined_length = (key ? strlen(key) : 0) + strlen(WEBSOCKET_GUID) + 1;
if (!key || combined_length > 8192) { /* no stack overflows please */
- fputs("HTTP/1.1 400 Bad Request\r\n"
- "Sec-WebSocket-Version: 7, 8, 13\r\n\r\n", ser->f);
+ websocket_bad_request(ser);
ao2_ref(protocol_handler, -1);
- return -1;
+ return 0;
+ }
+
+ if (ast_http_body_discard(ser)) {
+ websocket_bad_request(ser);
+ ao2_ref(protocol_handler, -1);
+ return 0;
}
if (!(session = ao2_alloc(sizeof(*session), session_destroy_fn))) {
ast_log(LOG_WARNING, "WebSocket connection from '%s' could not be accepted\n",
ast_sockaddr_stringify(&ser->remote_address));
- fputs("HTTP/1.1 400 Bad Request\r\n"
- "Sec-WebSocket-Version: 7, 8, 13\r\n\r\n", ser->f);
+ websocket_bad_request(ser);
ao2_ref(protocol_handler, -1);
- return -1;
+ return 0;
}
session->timeout = AST_DEFAULT_WEBSOCKET_WRITE_TIMEOUT;
@@ -729,21 +742,19 @@
/* Specification defined in http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-75 or completely unknown */
ast_log(LOG_WARNING, "WebSocket connection from '%s' could not be accepted - unsupported version '%d' chosen\n",
ast_sockaddr_stringify(&ser->remote_address), version ? version : 75);
- fputs("HTTP/1.1 400 Bad Request\r\n"
- "Sec-WebSocket-Version: 7, 8, 13\r\n\r\n", ser->f);
+ websocket_bad_request(ser);
ao2_ref(protocol_handler, -1);
- return -1;
+ return 0;
}
/* Enable keepalive on all sessions so the underlying user does not have to */
if (setsockopt(ser->fd, SOL_SOCKET, SO_KEEPALIVE, &flags, sizeof(flags))) {
ast_log(LOG_WARNING, "WebSocket connection from '%s' could not be accepted - failed to enable keepalive\n",
ast_sockaddr_stringify(&ser->remote_address));
- fputs("HTTP/1.1 400 Bad Request\r\n"
- "Sec-WebSocket-Version: 7, 8, 13\r\n\r\n", ser->f);
+ websocket_bad_request(ser);
ao2_ref(session, -1);
ao2_ref(protocol_handler, -1);
- return -1;
+ return 0;
}
ast_verb(2, "WebSocket connection from '%s' for protocol '%s' accepted using version '%d'\n", ast_sockaddr_stringify(&ser->remote_address), protocol ? : "", version);
@@ -757,6 +768,8 @@
session->secure = ser->ssl ? 1 : 0;
/* Give up ownership of the socket and pass it to the protocol handler */
+/* BUGBUG need to verify if we truly need to give up exclusive input from the socket. */
+ ast_tcptls_stream_set_exclusive_input(ser->stream_cookie, 0);
protocol_handler->callback(session, get_vars, headers);
ao2_ref(protocol_handler, -1);
Modified: team/rmudgett/http_persistent/res/res_phoneprov.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/http_persistent/res/res_phoneprov.c?view=diff&rev=417545&r1=417544&r2=417545
==============================================================================
--- team/rmudgett/http_persistent/res/res_phoneprov.c (original)
+++ team/rmudgett/http_persistent/res/res_phoneprov.c Fri Jun 27 14:49:40 2014
@@ -428,7 +428,7 @@
if (method != AST_HTTP_GET && method != AST_HTTP_HEAD) {
ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method");
- return -1;
+ return 0;
}
if (!(route = ao2_find(http_routes, &search_route, OBJ_POINTER))) {
@@ -542,12 +542,12 @@
out404:
ast_http_error(ser, 404, "Not Found", "Nothing to see here. Move along.");
- return -1;
+ return 0;
out500:
route = unref_route(route);
ast_http_error(ser, 500, "Internal Error", "An internal error has occured.");
- return -1;
+ return 0;
}
/*! \brief Build a route structure and add it to the list of available http routes
More information about the svn-commits
mailing list