2015-04-22 11:35:37 -07:00
|
|
|
/*
|
|
|
|
* libwebsockets - small server side websockets and web server implementation
|
|
|
|
*
|
|
|
|
* Copyright (C) 2010-2013 Andy Green <andy@warmcat.com>
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation:
|
|
|
|
* version 2.1 of the License.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
|
|
* MA 02110-1301 USA
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "private-libwebsockets.h"
|
2016-07-23 14:18:25 +08:00
|
|
|
|
2015-04-22 11:35:37 -07:00
|
|
|
#include "lextable-strings.h"
|
|
|
|
|
2016-07-23 14:18:25 +08:00
|
|
|
|
2015-04-22 11:35:37 -07:00
|
|
|
const unsigned char *lws_token_to_string(enum lws_token_indexes token)
|
|
|
|
{
|
|
|
|
if ((unsigned int)token >= ARRAY_SIZE(set))
|
|
|
|
return NULL;
|
2015-12-06 08:40:00 +08:00
|
|
|
|
2015-04-22 11:35:37 -07:00
|
|
|
return (unsigned char *)set[token];
|
|
|
|
}
|
|
|
|
|
2015-12-06 08:40:00 +08:00
|
|
|
int
|
2015-12-16 18:19:08 +08:00
|
|
|
lws_add_http_header_by_name(struct lws *wsi, const unsigned char *name,
|
2015-12-06 08:40:00 +08:00
|
|
|
const unsigned char *value, int length,
|
|
|
|
unsigned char **p, unsigned char *end)
|
2015-04-22 11:35:37 -07:00
|
|
|
{
|
|
|
|
#ifdef LWS_USE_HTTP2
|
2015-12-17 17:03:59 +08:00
|
|
|
if (wsi->mode == LWSCM_HTTP2_SERVING)
|
2015-12-16 18:19:08 +08:00
|
|
|
return lws_add_http2_header_by_name(wsi, name,
|
2015-12-06 08:40:00 +08:00
|
|
|
value, length, p, end);
|
2015-11-02 13:10:33 +08:00
|
|
|
#else
|
|
|
|
(void)wsi;
|
2015-04-22 11:35:37 -07:00
|
|
|
#endif
|
|
|
|
if (name) {
|
|
|
|
while (*p < end && *name)
|
|
|
|
*((*p)++) = *name++;
|
|
|
|
if (*p == end)
|
|
|
|
return 1;
|
|
|
|
*((*p)++) = ' ';
|
|
|
|
}
|
|
|
|
if (*p + length + 3 >= end)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
memcpy(*p, value, length);
|
|
|
|
*p += length;
|
|
|
|
*((*p)++) = '\x0d';
|
|
|
|
*((*p)++) = '\x0a';
|
2015-12-06 08:40:00 +08:00
|
|
|
|
2015-04-22 11:35:37 -07:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-12-16 18:19:08 +08:00
|
|
|
int lws_finalize_http_header(struct lws *wsi, unsigned char **p,
|
|
|
|
unsigned char *end)
|
2015-04-22 11:35:37 -07:00
|
|
|
{
|
|
|
|
#ifdef LWS_USE_HTTP2
|
2015-12-17 17:03:59 +08:00
|
|
|
if (wsi->mode == LWSCM_HTTP2_SERVING)
|
2015-04-22 11:35:37 -07:00
|
|
|
return 0;
|
2015-11-02 13:10:33 +08:00
|
|
|
#else
|
|
|
|
(void)wsi;
|
2015-04-22 11:35:37 -07:00
|
|
|
#endif
|
|
|
|
if ((long)(end - *p) < 3)
|
|
|
|
return 1;
|
|
|
|
*((*p)++) = '\x0d';
|
|
|
|
*((*p)++) = '\x0a';
|
2015-12-06 08:40:00 +08:00
|
|
|
|
2015-04-22 11:35:37 -07:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-12-06 08:40:00 +08:00
|
|
|
int
|
2015-12-16 18:19:08 +08:00
|
|
|
lws_add_http_header_by_token(struct lws *wsi, enum lws_token_indexes token,
|
2015-12-06 08:40:00 +08:00
|
|
|
const unsigned char *value, int length,
|
|
|
|
unsigned char **p, unsigned char *end)
|
2015-04-22 11:35:37 -07:00
|
|
|
{
|
|
|
|
const unsigned char *name;
|
|
|
|
#ifdef LWS_USE_HTTP2
|
2015-12-17 17:03:59 +08:00
|
|
|
if (wsi->mode == LWSCM_HTTP2_SERVING)
|
2015-12-16 18:19:08 +08:00
|
|
|
return lws_add_http2_header_by_token(wsi, token, value, length, p, end);
|
2015-04-22 11:35:37 -07:00
|
|
|
#endif
|
|
|
|
name = lws_token_to_string(token);
|
|
|
|
if (!name)
|
|
|
|
return 1;
|
2015-12-16 18:19:08 +08:00
|
|
|
return lws_add_http_header_by_name(wsi, name, value, length, p, end);
|
2015-04-22 11:35:37 -07:00
|
|
|
}
|
|
|
|
|
2015-12-16 18:19:08 +08:00
|
|
|
int lws_add_http_header_content_length(struct lws *wsi,
|
2015-12-06 08:40:00 +08:00
|
|
|
unsigned long content_length,
|
|
|
|
unsigned char **p, unsigned char *end)
|
2015-04-22 11:35:37 -07:00
|
|
|
{
|
|
|
|
char b[24];
|
|
|
|
int n;
|
|
|
|
|
|
|
|
n = sprintf(b, "%lu", content_length);
|
2015-12-17 17:03:59 +08:00
|
|
|
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH,
|
|
|
|
(unsigned char *)b, n, p, end))
|
2015-04-22 11:35:37 -07:00
|
|
|
return 1;
|
|
|
|
wsi->u.http.content_length = content_length;
|
|
|
|
wsi->u.http.content_remain = content_length;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-07-23 14:18:25 +08:00
|
|
|
STORE_IN_ROM static const char * const err400[] = {
|
2015-04-22 11:35:37 -07:00
|
|
|
"Bad Request",
|
|
|
|
"Unauthorized",
|
|
|
|
"Payment Required",
|
|
|
|
"Forbidden",
|
|
|
|
"Not Found",
|
|
|
|
"Method Not Allowed",
|
|
|
|
"Not Acceptable",
|
|
|
|
"Proxy Auth Required",
|
|
|
|
"Request Timeout",
|
|
|
|
"Conflict",
|
|
|
|
"Gone",
|
|
|
|
"Length Required",
|
|
|
|
"Precondition Failed",
|
|
|
|
"Request Entity Too Large",
|
|
|
|
"Request URI too Long",
|
|
|
|
"Unsupported Media Type",
|
|
|
|
"Requested Range Not Satisfiable",
|
|
|
|
"Expectation Failed"
|
|
|
|
};
|
|
|
|
|
2016-07-23 14:18:25 +08:00
|
|
|
STORE_IN_ROM static const char * const err500[] = {
|
2015-04-22 11:35:37 -07:00
|
|
|
"Internal Server Error",
|
|
|
|
"Not Implemented",
|
|
|
|
"Bad Gateway",
|
|
|
|
"Service Unavailable",
|
|
|
|
"Gateway Timeout",
|
|
|
|
"HTTP Version Not Supported"
|
|
|
|
};
|
|
|
|
|
2015-12-06 08:40:00 +08:00
|
|
|
int
|
2015-12-17 17:03:59 +08:00
|
|
|
lws_add_http_header_status(struct lws *wsi, unsigned int code,
|
|
|
|
unsigned char **p, unsigned char *end)
|
2015-04-22 11:35:37 -07:00
|
|
|
{
|
2016-08-27 17:07:06 +08:00
|
|
|
const struct lws_protocol_vhost_options *headers;
|
2015-04-22 11:35:37 -07:00
|
|
|
unsigned char code_and_desc[60];
|
2016-04-15 12:29:06 +08:00
|
|
|
const char *description = "", *p1;
|
2015-04-22 11:35:37 -07:00
|
|
|
int n;
|
2016-07-23 14:18:25 +08:00
|
|
|
STORE_IN_ROM static const char * const hver[] = {
|
2016-04-15 12:29:06 +08:00
|
|
|
"HTTP/1.0", "HTTP/1.1", "HTTP/2"
|
2016-04-15 12:00:23 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
#ifdef LWS_WITH_ACCESS_LOG
|
|
|
|
wsi->access_log.response = code;
|
|
|
|
#endif
|
2015-04-22 11:35:37 -07:00
|
|
|
|
|
|
|
#ifdef LWS_USE_HTTP2
|
2015-12-17 17:03:59 +08:00
|
|
|
if (wsi->mode == LWSCM_HTTP2_SERVING)
|
2015-12-16 18:19:08 +08:00
|
|
|
return lws_add_http2_header_status(wsi, code, p, end);
|
2015-04-22 11:35:37 -07:00
|
|
|
#endif
|
|
|
|
if (code >= 400 && code < (400 + ARRAY_SIZE(err400)))
|
|
|
|
description = err400[code - 400];
|
|
|
|
if (code >= 500 && code < (500 + ARRAY_SIZE(err500)))
|
|
|
|
description = err500[code - 500];
|
|
|
|
|
2016-04-15 12:29:06 +08:00
|
|
|
if (code == 200)
|
|
|
|
description = "OK";
|
|
|
|
|
2016-04-22 08:53:49 +08:00
|
|
|
if (code == 304)
|
|
|
|
description = "Not Modified";
|
|
|
|
else
|
|
|
|
if (code >= 300 && code < 400)
|
|
|
|
description = "Redirect";
|
2016-04-15 12:29:06 +08:00
|
|
|
|
|
|
|
if (wsi->u.http.request_version < ARRAY_SIZE(hver))
|
|
|
|
p1 = hver[wsi->u.http.request_version];
|
|
|
|
else
|
|
|
|
p1 = hver[0];
|
|
|
|
|
2016-04-15 12:00:23 +08:00
|
|
|
n = sprintf((char *)code_and_desc, "%s %u %s",
|
2016-04-15 12:29:06 +08:00
|
|
|
p1, code, description);
|
2015-04-22 11:35:37 -07:00
|
|
|
|
2016-04-15 13:33:52 +08:00
|
|
|
if (lws_add_http_header_by_name(wsi, NULL, code_and_desc,
|
|
|
|
n, p, end))
|
|
|
|
return 1;
|
|
|
|
|
2016-08-27 17:07:06 +08:00
|
|
|
headers = wsi->vhost->headers;
|
|
|
|
while (headers) {
|
|
|
|
if (lws_add_http_header_by_name(wsi,
|
|
|
|
(const unsigned char *)headers->name,
|
|
|
|
(unsigned char *)headers->value,
|
|
|
|
strlen(headers->value), p, end))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
headers = headers->next;
|
|
|
|
}
|
|
|
|
|
2016-04-15 13:33:52 +08:00
|
|
|
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_SERVER,
|
|
|
|
(unsigned char *)
|
|
|
|
wsi->context->server_string,
|
|
|
|
wsi->context->server_string_len,
|
|
|
|
p, end))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
if (wsi->vhost->options & LWS_SERVER_OPTION_STS)
|
|
|
|
if (lws_add_http_header_by_name(wsi, (unsigned char *)
|
|
|
|
"Strict-Transport-Security:",
|
|
|
|
(unsigned char *)"max-age=15768000 ; "
|
|
|
|
"includeSubDomains", 36, p, end))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
return 0;
|
2015-04-22 11:35:37 -07:00
|
|
|
}
|
|
|
|
|
2015-12-06 08:40:00 +08:00
|
|
|
LWS_VISIBLE int
|
2016-02-20 07:53:24 +08:00
|
|
|
lws_return_http_status(struct lws *wsi, unsigned int code,
|
|
|
|
const char *html_body)
|
2015-04-22 11:35:37 -07:00
|
|
|
{
|
2015-12-17 18:25:25 +08:00
|
|
|
struct lws_context *context = lws_get_context(wsi);
|
2016-01-19 03:34:24 +08:00
|
|
|
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
|
|
|
unsigned char *p = pt->serv_buf + LWS_PRE;
|
2016-02-20 07:53:24 +08:00
|
|
|
unsigned char *start = p, *body = p + 512;
|
2016-05-19 12:34:35 +08:00
|
|
|
unsigned char *end = p + context->pt_serv_buf_size - LWS_PRE;
|
2016-02-20 07:53:24 +08:00
|
|
|
int n, m, len;
|
|
|
|
char slen[20];
|
2015-04-22 11:35:37 -07:00
|
|
|
|
|
|
|
if (!html_body)
|
|
|
|
html_body = "";
|
|
|
|
|
2016-02-20 07:53:24 +08:00
|
|
|
len = sprintf((char *)body, "<html><body><h1>%u</h1>%s</body></html>",
|
|
|
|
code, html_body);
|
|
|
|
|
2015-12-16 18:19:08 +08:00
|
|
|
if (lws_add_http_header_status(wsi, code, &p, end))
|
2015-04-22 11:35:37 -07:00
|
|
|
return 1;
|
2016-04-15 13:33:52 +08:00
|
|
|
|
2015-12-16 18:19:08 +08:00
|
|
|
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE,
|
2015-12-06 08:40:00 +08:00
|
|
|
(unsigned char *)"text/html", 9,
|
|
|
|
&p, end))
|
2015-04-22 11:35:37 -07:00
|
|
|
return 1;
|
2016-02-20 07:53:24 +08:00
|
|
|
n = sprintf(slen, "%d", len);
|
|
|
|
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH,
|
|
|
|
(unsigned char *)slen, n,
|
|
|
|
&p, end))
|
|
|
|
return 1;
|
|
|
|
|
2015-12-16 18:19:08 +08:00
|
|
|
if (lws_finalize_http_header(wsi, &p, end))
|
2015-04-22 11:35:37 -07:00
|
|
|
return 1;
|
|
|
|
|
2015-12-04 08:43:54 +08:00
|
|
|
m = lws_write(wsi, start, p - start, LWS_WRITE_HTTP_HEADERS);
|
2015-04-22 11:35:37 -07:00
|
|
|
if (m != (int)(p - start))
|
|
|
|
return 1;
|
|
|
|
|
2016-02-20 07:53:24 +08:00
|
|
|
m = lws_write(wsi, body, len, LWS_WRITE_HTTP);
|
2015-04-22 11:35:37 -07:00
|
|
|
|
|
|
|
return m != n;
|
|
|
|
}
|
2016-04-15 20:09:36 +08:00
|
|
|
|
|
|
|
LWS_VISIBLE int
|
2016-04-25 10:04:49 +08:00
|
|
|
lws_http_redirect(struct lws *wsi, int code, const unsigned char *loc, int len,
|
2016-04-15 20:09:36 +08:00
|
|
|
unsigned char **p, unsigned char *end)
|
|
|
|
{
|
|
|
|
unsigned char *start = *p;
|
|
|
|
int n;
|
|
|
|
|
2016-04-25 10:04:49 +08:00
|
|
|
if (lws_add_http_header_status(wsi, code, p, end))
|
2016-04-15 20:09:36 +08:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (lws_add_http_header_by_token(wsi,
|
|
|
|
WSI_TOKEN_HTTP_LOCATION,
|
|
|
|
loc, len, p, end))
|
|
|
|
return -1;
|
|
|
|
/*
|
|
|
|
* if we're going with http/1.1 and keepalive,
|
|
|
|
* we have to give fake content metadata so the
|
|
|
|
* client knows we completed the transaction and
|
|
|
|
* it can do the redirect...
|
|
|
|
*/
|
|
|
|
if (lws_add_http_header_by_token(wsi,
|
|
|
|
WSI_TOKEN_HTTP_CONTENT_TYPE,
|
|
|
|
(unsigned char *)"text/html", 9,
|
|
|
|
p, end))
|
|
|
|
return -1;
|
|
|
|
if (lws_add_http_header_by_token(wsi,
|
|
|
|
WSI_TOKEN_HTTP_CONTENT_LENGTH,
|
|
|
|
(unsigned char *)"0", 1, p, end))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (lws_finalize_http_header(wsi, p, end))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
n = lws_write(wsi, start, *p - start,
|
|
|
|
LWS_WRITE_HTTP_HEADERS);
|
|
|
|
|
|
|
|
return n;
|
|
|
|
}
|