mirror of
https://github.com/oopuuu/zTC1.git
synced 2025-12-19 08:23:22 +08:00
修复mico-sdk错误
This commit is contained in:
@@ -1,399 +1,399 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file httpd_handle.c
|
||||
* @author QQ DING
|
||||
* @version V1.0.0
|
||||
* @date 1-September-2015
|
||||
* @brief This is the main processing of an HTTP request. There could be three
|
||||
* types of requests, a WSGI, an SSI or a file. This file contains
|
||||
* routines that deal with this.
|
||||
******************************************************************************
|
||||
*
|
||||
* The MIT License
|
||||
* Copyright (c) 2014 MXCHIP Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
* IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*****************************************************************************
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include "httpd.h"
|
||||
#include "http_parse.h"
|
||||
#include "http-strings.h"
|
||||
|
||||
#include "httpd_priv.h"
|
||||
|
||||
#ifdef CONFIG_ENABLE_HTTPS
|
||||
|
||||
|
||||
extern tls_handle_t httpd_tls_handle;
|
||||
#endif /* ENABLE_HTTPS */
|
||||
|
||||
#define STATE_WAITING 0
|
||||
#define STATE_OUTPUT 1
|
||||
|
||||
static httpd_request_t httpd_req;
|
||||
|
||||
/* Send the chunk header, which is just an ascii size followed by a cr lf.
|
||||
*/
|
||||
#define CHUNK_SIZE_DIGITS 0x10
|
||||
int httpd_send_chunk_begin(int conn, int size)
|
||||
{
|
||||
|
||||
int err;
|
||||
char buf[CHUNK_SIZE_DIGITS];
|
||||
int i;
|
||||
int digit;
|
||||
int begin = 1;
|
||||
|
||||
for (i = CHUNK_SIZE_DIGITS - 1; i >= 0; i--) {
|
||||
digit = size & 0xf;
|
||||
if (!begin && !size) {
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
buf[i] = (digit > 9) ? digit - 0xA + 'a' : digit + '0';
|
||||
size = size >> 4;
|
||||
begin = 0;
|
||||
}
|
||||
err = httpd_send(conn, &buf[i], CHUNK_SIZE_DIGITS - i);
|
||||
if (err != kNoErr) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = httpd_send_crlf(conn);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Send the last chunk which is simply an ascii "0\r\n\r\n"
|
||||
*/
|
||||
int httpd_send_last_chunk(int conn)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = httpd_send(conn, http_last_chunk,
|
||||
sizeof(http_last_chunk) - 1);
|
||||
|
||||
if (err != kNoErr) {
|
||||
httpd_d("Send last chunk failed");
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Send one chunk of data of a given size
|
||||
*/
|
||||
int httpd_send_chunk(int conn, const char *buf, int len)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (len) {
|
||||
/* Send chunk begin header */
|
||||
err = httpd_send_chunk_begin(conn, len);
|
||||
if (err != kNoErr)
|
||||
return err;
|
||||
/* Send our data */
|
||||
err = httpd_send(conn, buf, len);
|
||||
if (err != kNoErr)
|
||||
return err;
|
||||
/* Send chunk end indicator */
|
||||
err = httpd_send_crlf(conn);
|
||||
if (err != kNoErr)
|
||||
return err;
|
||||
} else {
|
||||
/* Length is 0, last chunk */
|
||||
err = httpd_send(conn, http_last_chunk,
|
||||
sizeof(http_last_chunk) - 1);
|
||||
if (err != kNoErr)
|
||||
return err;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*Helper function to send a buffer over a connection.
|
||||
*/
|
||||
int httpd_send(int conn, const char *buf, int len)
|
||||
{
|
||||
int num;
|
||||
do {
|
||||
#ifdef CONFIG_ENABLE_HTTPS
|
||||
if (httpd_is_https_active())
|
||||
num = tls_send(httpd_tls_handle, buf, len);
|
||||
else
|
||||
#endif /* ENABLE_HTTPS */
|
||||
num = send(conn, buf, len, 0);
|
||||
if (num < 0) {
|
||||
httpd_d("send() failed: %d" ,conn);
|
||||
return -kInProgressErr;
|
||||
}
|
||||
len -= num;
|
||||
buf += num;
|
||||
} while (len > 0);
|
||||
|
||||
|
||||
return kNoErr;
|
||||
}
|
||||
|
||||
int httpd_recv(int fd, void *buf, size_t n, int flags)
|
||||
{
|
||||
#ifdef CONFIG_ENABLE_HTTPS
|
||||
if (httpd_is_https_active())
|
||||
return tls_recv(httpd_tls_handle, buf, n);
|
||||
else
|
||||
#endif /* ENABLE_HTTPS */
|
||||
return recv(fd, buf, n, flags);
|
||||
}
|
||||
|
||||
int httpd_send_hdr_from_code(int sock, int stat_code,
|
||||
enum http_content_type content_type)
|
||||
{
|
||||
const char *str;
|
||||
unsigned int str_len;
|
||||
/*
|
||||
* Set the HTTP Response Status 200 OK, 404 NOT FOUND etc.
|
||||
* Also set the Transfer-Encoding to chunked.
|
||||
*/
|
||||
switch (stat_code) {
|
||||
case -WM_E_HTTPD_HANDLER_404:
|
||||
str = http_header_404;
|
||||
str_len = strlen(http_header_404);
|
||||
break;
|
||||
case -WM_E_HTTPD_HANDLER_400:
|
||||
str = http_header_400;
|
||||
str_len = strlen(http_header_400);
|
||||
break;
|
||||
case -WM_E_HTTPD_HANDLER_500:
|
||||
str = http_header_500;
|
||||
str_len = strlen(http_header_500);
|
||||
break;
|
||||
default:
|
||||
/* The handler doesn't want an HTTP error code, but would return
|
||||
* 200 OK with an error in the response */
|
||||
str = http_header_200;
|
||||
str_len = strlen(http_header_200);
|
||||
break;
|
||||
}
|
||||
|
||||
if (httpd_send(sock, str, str_len) != kNoErr) {
|
||||
return -kInProgressErr;
|
||||
}
|
||||
|
||||
/* Send the Content-Type */
|
||||
switch (content_type) {
|
||||
case HTTP_CONTENT_JSON:
|
||||
str = http_content_type_json_nocache;
|
||||
str_len = sizeof(http_content_type_json_nocache) - 1;
|
||||
break;
|
||||
case HTTP_CONTENT_XML:
|
||||
str = http_content_type_xml_nocache;
|
||||
str_len = sizeof(http_content_type_xml_nocache) - 1;
|
||||
break;
|
||||
case HTTP_CONTENT_HTML:
|
||||
str = http_content_type_html;
|
||||
str_len = sizeof(http_content_type_html) - 1;
|
||||
break;
|
||||
case HTTP_CONTENT_JPEG:
|
||||
str = http_content_type_jpg;
|
||||
str_len = sizeof(http_content_type_jpg) - 1;
|
||||
break;
|
||||
default:
|
||||
str = http_content_type_plain;
|
||||
str_len = sizeof(http_content_type_plain) - 1;
|
||||
break;
|
||||
}
|
||||
if (httpd_send(sock, str, str_len) != kNoErr) {
|
||||
return -kInProgressErr;
|
||||
}
|
||||
return kNoErr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* set the system wide error. */
|
||||
static char httpd_error[HTTPD_MAX_ERROR_STRING + 1];
|
||||
void httpd_set_error(const char *fmt, ...)
|
||||
{
|
||||
va_list argp;
|
||||
|
||||
va_start(argp, fmt);
|
||||
vsnprintf(httpd_error, HTTPD_MAX_ERROR_STRING + 1, fmt, argp);
|
||||
va_end(argp);
|
||||
|
||||
httpd_d("http set err");
|
||||
}
|
||||
|
||||
/* Helper function to send an error.
|
||||
*/
|
||||
int httpd_send_error(int conn, int http_error)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
switch (http_error) {
|
||||
case HTTP_404:
|
||||
err = httpd_send(conn, http_header_404,
|
||||
strlen(http_header_404));
|
||||
break;
|
||||
case HTTP_500:
|
||||
err = httpd_send(conn, http_header_500,
|
||||
strlen(http_header_500));
|
||||
break;
|
||||
|
||||
case HTTP_505:
|
||||
err = httpd_send(conn, http_header_505,
|
||||
strlen(http_header_505));
|
||||
break;
|
||||
}
|
||||
|
||||
if (err != kNoErr) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = httpd_send(conn, http_header_type_chunked,
|
||||
strlen(http_header_type_chunked));
|
||||
if (err != kNoErr) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = httpd_send(conn, http_content_type_plain,
|
||||
sizeof(http_content_type_plain) - 1);
|
||||
if (err != kNoErr) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = httpd_send_crlf(conn);
|
||||
if (err != kNoErr) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = httpd_send_chunk(conn, httpd_error, strlen(httpd_error));
|
||||
if (err != kNoErr) {
|
||||
return err;
|
||||
}
|
||||
return httpd_send_last_chunk(conn);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* @pre Only first line of HTTP header (which has the resource name) has
|
||||
* been read from the socket. We need to read the remaining header and the
|
||||
* data after that.
|
||||
*/
|
||||
void httpd_purge_socket_data(httpd_request_t *req, char *msg_in,
|
||||
int msg_in_len, int conn)
|
||||
{
|
||||
int status = httpd_parse_hdr_tags(req, conn, msg_in, msg_in_len);
|
||||
if (status != kNoErr) {
|
||||
/* We were unsuccessful in purging the socket.*/
|
||||
httpd_d("Unable to purge socket: %d", status);
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned data_remaining = req->body_nbytes;
|
||||
|
||||
while (data_remaining) {
|
||||
unsigned to_read = msg_in_len >= data_remaining ?
|
||||
data_remaining : msg_in_len;
|
||||
int actually_read = httpd_recv(conn, msg_in, to_read, 0);
|
||||
if (actually_read < 0) {
|
||||
httpd_d("Unable to read content."
|
||||
"Was purging socket data");
|
||||
return;
|
||||
}
|
||||
data_remaining -= actually_read;
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle an incoming message (request) from the client. This is the
|
||||
* main processing function of the HTTPD.
|
||||
*/
|
||||
int httpd_handle_message(int conn)
|
||||
{
|
||||
int err;
|
||||
int req_line_len;
|
||||
char msg_in[128];
|
||||
|
||||
/* clear out the httpd_req structure */
|
||||
memset(&httpd_req, 0x00, sizeof(httpd_req));
|
||||
|
||||
httpd_req.sock = conn;
|
||||
|
||||
/* Read the first line of the HTTP header */
|
||||
req_line_len = htsys_getln_soc(conn, msg_in, sizeof(msg_in));
|
||||
if (req_line_len == 0)
|
||||
return HTTPD_DONE;
|
||||
|
||||
if (req_line_len < 0) {
|
||||
httpd_d("Could not read from socket");
|
||||
return -kInProgressErr;
|
||||
}
|
||||
|
||||
/* Parse the first line of the header */
|
||||
err = httpd_parse_hdr_main(msg_in, &httpd_req);
|
||||
if (err == -WM_E_HTTPD_NOTSUPP)
|
||||
/* Send 505 HTTP Version not supported */
|
||||
return httpd_send_error(conn, HTTP_505);
|
||||
else if (err != kNoErr) {
|
||||
/* Send 500 Internal Server Error */
|
||||
return httpd_send_error(conn, HTTP_500);
|
||||
}
|
||||
|
||||
/* set a generic error that can be overridden by the wsgi handling. */
|
||||
httpd_d("Presetting");
|
||||
|
||||
/* Web Services Gateway Interface branch point:
|
||||
* At this point we have the request type (httpd_req.type) and the path
|
||||
* (httpd_req.filename) and all the headers waiting to be read from
|
||||
* the socket.
|
||||
*
|
||||
* The call bellow will iterate through all the url patterns and
|
||||
* invoke the handlers that match the request type and pattern. If
|
||||
* request type and url patern match, invoke the handler.
|
||||
*/
|
||||
err = httpd_wsgi(&httpd_req);
|
||||
|
||||
if (err == HTTPD_DONE) {
|
||||
httpd_d("Done processing request.");
|
||||
return kNoErr;
|
||||
} else if (err == -WM_E_HTTPD_NO_HANDLER) {
|
||||
httpd_d("No handler for the given URL %s was found",
|
||||
httpd_req.filename);
|
||||
/*
|
||||
* We have not yet read the complete data from the current
|
||||
* request, from the socket. We are in an error state and
|
||||
* we wish to cancel this HTTP transaction. We sent
|
||||
* appropriate message to the client and read (flush) out
|
||||
* all the pending data in the socket. We let the client
|
||||
* close the socket for us, if necessary.
|
||||
*/
|
||||
httpd_purge_socket_data(&httpd_req, msg_in,
|
||||
sizeof(msg_in), conn);
|
||||
httpd_set_error("File %s not_found", httpd_req.filename);
|
||||
httpd_send_error(conn, HTTP_404);
|
||||
return kNoErr;
|
||||
} else {
|
||||
httpd_d("WSGI handler failed.");
|
||||
/* Send 500 Internal Server Error */
|
||||
return httpd_send_error(conn, HTTP_500);
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file httpd_handle.c
|
||||
* @author QQ DING
|
||||
* @version V1.0.0
|
||||
* @date 1-September-2015
|
||||
* @brief This is the main processing of an HTTP request. There could be three
|
||||
* types of requests, a WSGI, an SSI or a file. This file contains
|
||||
* routines that deal with this.
|
||||
******************************************************************************
|
||||
*
|
||||
* The MIT License
|
||||
* Copyright (c) 2014 MXCHIP Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
* IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*****************************************************************************
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include "httpd.h"
|
||||
#include "http_parse.h"
|
||||
#include "http-strings.h"
|
||||
|
||||
#include "httpd_priv.h"
|
||||
|
||||
#ifdef CONFIG_ENABLE_HTTPS
|
||||
|
||||
|
||||
extern tls_handle_t httpd_tls_handle;
|
||||
#endif /* ENABLE_HTTPS */
|
||||
|
||||
#define STATE_WAITING 0
|
||||
#define STATE_OUTPUT 1
|
||||
|
||||
static httpd_request_t httpd_req;
|
||||
|
||||
/* Send the chunk header, which is just an ascii size followed by a cr lf.
|
||||
*/
|
||||
#define CHUNK_SIZE_DIGITS 0x10
|
||||
int httpd_send_chunk_begin(int conn, int size)
|
||||
{
|
||||
|
||||
int err;
|
||||
char buf[CHUNK_SIZE_DIGITS];
|
||||
int i;
|
||||
int digit;
|
||||
int begin = 1;
|
||||
|
||||
for (i = CHUNK_SIZE_DIGITS - 1; i >= 0; i--) {
|
||||
digit = size & 0xf;
|
||||
if (!begin && !size) {
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
buf[i] = (digit > 9) ? digit - 0xA + 'a' : digit + '0';
|
||||
size = size >> 4;
|
||||
begin = 0;
|
||||
}
|
||||
err = httpd_send(conn, &buf[i], CHUNK_SIZE_DIGITS - i);
|
||||
if (err != kNoErr) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = httpd_send_crlf(conn);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Send the last chunk which is simply an ascii "0\r\n\r\n"
|
||||
*/
|
||||
int httpd_send_last_chunk(int conn)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = httpd_send(conn, http_last_chunk,
|
||||
sizeof(http_last_chunk) - 1);
|
||||
|
||||
if (err != kNoErr) {
|
||||
httpd_d("Send last chunk failed");
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Send one chunk of data of a given size
|
||||
*/
|
||||
int httpd_send_chunk(int conn, const char *buf, int len)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (len) {
|
||||
/* Send chunk begin header */
|
||||
err = httpd_send_chunk_begin(conn, len);
|
||||
if (err != kNoErr)
|
||||
return err;
|
||||
/* Send our data */
|
||||
err = httpd_send(conn, buf, len);
|
||||
if (err != kNoErr)
|
||||
return err;
|
||||
/* Send chunk end indicator */
|
||||
err = httpd_send_crlf(conn);
|
||||
if (err != kNoErr)
|
||||
return err;
|
||||
} else {
|
||||
/* Length is 0, last chunk */
|
||||
err = httpd_send(conn, http_last_chunk,
|
||||
sizeof(http_last_chunk) - 1);
|
||||
if (err != kNoErr)
|
||||
return err;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*Helper function to send a buffer over a connection.
|
||||
*/
|
||||
int httpd_send(int conn, const char *buf, int len)
|
||||
{
|
||||
int num;
|
||||
do {
|
||||
#ifdef CONFIG_ENABLE_HTTPS
|
||||
if (httpd_is_https_active())
|
||||
num = tls_send(httpd_tls_handle, buf, len);
|
||||
else
|
||||
#endif /* ENABLE_HTTPS */
|
||||
num = send(conn, buf, len, 0);
|
||||
if (num < 0) {
|
||||
httpd_d("send() failed: %d" ,conn);
|
||||
return -kInProgressErr;
|
||||
}
|
||||
len -= num;
|
||||
buf += num;
|
||||
} while (len > 0);
|
||||
|
||||
|
||||
return kNoErr;
|
||||
}
|
||||
|
||||
int httpd_recv(int fd, void *buf, size_t n, int flags)
|
||||
{
|
||||
#ifdef CONFIG_ENABLE_HTTPS
|
||||
if (httpd_is_https_active())
|
||||
return tls_recv(httpd_tls_handle, buf, n);
|
||||
else
|
||||
#endif /* ENABLE_HTTPS */
|
||||
return recv(fd, buf, n, flags);
|
||||
}
|
||||
|
||||
int httpd_send_hdr_from_code(int sock, int stat_code,
|
||||
enum http_content_type content_type)
|
||||
{
|
||||
const char *str;
|
||||
unsigned int str_len;
|
||||
/*
|
||||
* Set the HTTP Response Status 200 OK, 404 NOT FOUND etc.
|
||||
* Also set the Transfer-Encoding to chunked.
|
||||
*/
|
||||
switch (stat_code) {
|
||||
case -WM_E_HTTPD_HANDLER_404:
|
||||
str = http_header_404;
|
||||
str_len = strlen(http_header_404);
|
||||
break;
|
||||
case -WM_E_HTTPD_HANDLER_400:
|
||||
str = http_header_400;
|
||||
str_len = strlen(http_header_400);
|
||||
break;
|
||||
case -WM_E_HTTPD_HANDLER_500:
|
||||
str = http_header_500;
|
||||
str_len = strlen(http_header_500);
|
||||
break;
|
||||
default:
|
||||
/* The handler doesn't want an HTTP error code, but would return
|
||||
* 200 OK with an error in the response */
|
||||
str = http_header_200;
|
||||
str_len = strlen(http_header_200);
|
||||
break;
|
||||
}
|
||||
|
||||
if (httpd_send(sock, str, str_len) != kNoErr) {
|
||||
return -kInProgressErr;
|
||||
}
|
||||
|
||||
/* Send the Content-Type */
|
||||
switch (content_type) {
|
||||
case HTTP_CONTENT_JSON:
|
||||
str = http_content_type_json_nocache;
|
||||
str_len = sizeof(http_content_type_json_nocache) - 1;
|
||||
break;
|
||||
case HTTP_CONTENT_XML:
|
||||
str = http_content_type_xml_nocache;
|
||||
str_len = sizeof(http_content_type_xml_nocache) - 1;
|
||||
break;
|
||||
case HTTP_CONTENT_HTML:
|
||||
str = http_content_type_html;
|
||||
str_len = sizeof(http_content_type_html) - 1;
|
||||
break;
|
||||
case HTTP_CONTENT_JPEG:
|
||||
str = http_content_type_jpg;
|
||||
str_len = sizeof(http_content_type_jpg) - 1;
|
||||
break;
|
||||
default:
|
||||
str = http_content_type_plain;
|
||||
str_len = sizeof(http_content_type_plain) - 1;
|
||||
break;
|
||||
}
|
||||
if (httpd_send(sock, str, str_len) != kNoErr) {
|
||||
return -kInProgressErr;
|
||||
}
|
||||
return kNoErr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* set the system wide error. */
|
||||
static char httpd_error[HTTPD_MAX_ERROR_STRING + 1];
|
||||
void httpd_set_error(const char *fmt, ...)
|
||||
{
|
||||
va_list argp;
|
||||
|
||||
va_start(argp, fmt);
|
||||
vsnprintf(httpd_error, HTTPD_MAX_ERROR_STRING + 1, fmt, argp);
|
||||
va_end(argp);
|
||||
|
||||
httpd_d("http set err");
|
||||
}
|
||||
|
||||
/* Helper function to send an error.
|
||||
*/
|
||||
int httpd_send_error(int conn, int http_error)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
switch (http_error) {
|
||||
case HTTP_404:
|
||||
err = httpd_send(conn, http_header_404,
|
||||
strlen(http_header_404));
|
||||
break;
|
||||
case HTTP_500:
|
||||
err = httpd_send(conn, http_header_500,
|
||||
strlen(http_header_500));
|
||||
break;
|
||||
|
||||
case HTTP_505:
|
||||
err = httpd_send(conn, http_header_505,
|
||||
strlen(http_header_505));
|
||||
break;
|
||||
}
|
||||
|
||||
if (err != kNoErr) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = httpd_send(conn, http_header_type_chunked,
|
||||
strlen(http_header_type_chunked));
|
||||
if (err != kNoErr) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = httpd_send(conn, http_content_type_plain,
|
||||
sizeof(http_content_type_plain) - 1);
|
||||
if (err != kNoErr) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = httpd_send_crlf(conn);
|
||||
if (err != kNoErr) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = httpd_send_chunk(conn, httpd_error, strlen(httpd_error));
|
||||
if (err != kNoErr) {
|
||||
return err;
|
||||
}
|
||||
return httpd_send_last_chunk(conn);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* @pre Only first line of HTTP header (which has the resource name) has
|
||||
* been read from the socket. We need to read the remaining header and the
|
||||
* data after that.
|
||||
*/
|
||||
void httpd_purge_socket_data(httpd_request_t *req, char *msg_in,
|
||||
int msg_in_len, int conn)
|
||||
{
|
||||
int status = httpd_parse_hdr_tags(req, conn, msg_in, msg_in_len);
|
||||
if (status != kNoErr) {
|
||||
/* We were unsuccessful in purging the socket.*/
|
||||
httpd_d("Unable to purge socket: %d", status);
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned data_remaining = req->body_nbytes;
|
||||
|
||||
while (data_remaining) {
|
||||
unsigned to_read = msg_in_len >= data_remaining ?
|
||||
data_remaining : msg_in_len;
|
||||
int actually_read = httpd_recv(conn, msg_in, to_read, 0);
|
||||
if (actually_read < 0) {
|
||||
httpd_d("Unable to read content."
|
||||
"Was purging socket data");
|
||||
return;
|
||||
}
|
||||
data_remaining -= actually_read;
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle an incoming message (request) from the client. This is the
|
||||
* main processing function of the HTTPD.
|
||||
*/
|
||||
int httpd_handle_message(int conn)
|
||||
{
|
||||
int err;
|
||||
int req_line_len;
|
||||
char msg_in[128];
|
||||
|
||||
/* clear out the httpd_req structure */
|
||||
memset(&httpd_req, 0x00, sizeof(httpd_req));
|
||||
|
||||
httpd_req.sock = conn;
|
||||
|
||||
/* Read the first line of the HTTP header */
|
||||
req_line_len = htsys_getln_soc(conn, msg_in, sizeof(msg_in));
|
||||
if (req_line_len == 0)
|
||||
return HTTPD_DONE;
|
||||
|
||||
if (req_line_len < 0) {
|
||||
httpd_d("Could not read from socket");
|
||||
return -kInProgressErr;
|
||||
}
|
||||
|
||||
/* Parse the first line of the header */
|
||||
err = httpd_parse_hdr_main(msg_in, &httpd_req);
|
||||
if (err == -WM_E_HTTPD_NOTSUPP)
|
||||
/* Send 505 HTTP Version not supported */
|
||||
return httpd_send_error(conn, HTTP_505);
|
||||
else if (err != kNoErr) {
|
||||
/* Send 500 Internal Server Error */
|
||||
return httpd_send_error(conn, HTTP_500);
|
||||
}
|
||||
|
||||
/* set a generic error that can be overridden by the wsgi handling. */
|
||||
httpd_d("Presetting");
|
||||
|
||||
/* Web Services Gateway Interface branch point:
|
||||
* At this point we have the request type (httpd_req.type) and the path
|
||||
* (httpd_req.filename) and all the headers waiting to be read from
|
||||
* the socket.
|
||||
*
|
||||
* The call bellow will iterate through all the url patterns and
|
||||
* invoke the handlers that match the request type and pattern. If
|
||||
* request type and url patern match, invoke the handler.
|
||||
*/
|
||||
err = httpd_wsgi(&httpd_req);
|
||||
|
||||
if (err == HTTPD_DONE) {
|
||||
httpd_d("Done processing request.");
|
||||
return kNoErr;
|
||||
} else if (err == -WM_E_HTTPD_NO_HANDLER) {
|
||||
httpd_d("No handler for the given URL %s was found",
|
||||
httpd_req.filename);
|
||||
/*
|
||||
* We have not yet read the complete data from the current
|
||||
* request, from the socket. We are in an error state and
|
||||
* we wish to cancel this HTTP transaction. We sent
|
||||
* appropriate message to the client and read (flush) out
|
||||
* all the pending data in the socket. We let the client
|
||||
* close the socket for us, if necessary.
|
||||
*/
|
||||
httpd_purge_socket_data(&httpd_req, msg_in,
|
||||
sizeof(msg_in), conn);
|
||||
httpd_set_error("File %s not_found", httpd_req.filename);
|
||||
httpd_send_error(conn, HTTP_404);
|
||||
return kNoErr;
|
||||
} else {
|
||||
httpd_d("WSGI handler failed.");
|
||||
/* Send 500 Internal Server Error */
|
||||
return httpd_send_error(conn, HTTP_500);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user