Files
ttyd/src/http.c
Shuanglei Tao d1d5336af1 http: lws_snprintf -> snprintf
lws_snprintf is not available in libwebsockets 1.7.1
2018-08-18 17:24:57 +08:00

162 lines
6.1 KiB
C

#include <string.h>
#include <libwebsockets.h>
#include "server.h"
#include "html.h"
int
check_auth(struct lws *wsi) {
if (server->credential == NULL)
return 0;
int hdr_length = lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_AUTHORIZATION);
char buf[hdr_length + 1];
int len = lws_hdr_copy(wsi, buf, sizeof(buf), WSI_TOKEN_HTTP_AUTHORIZATION);
if (len > 0) {
// extract base64 text from authorization header
char *ptr = &buf[0];
char *token, *b64_text = NULL;
int i = 1;
while ((token = strsep(&ptr, " ")) != NULL) {
if (strlen(token) == 0)
continue;
if (i++ == 2) {
b64_text = token;
break;
}
}
if (b64_text != NULL && !strcmp(b64_text, server->credential))
return 0;
}
unsigned char buffer[1024 + LWS_PRE], *p, *end;
p = buffer + LWS_PRE;
end = p + sizeof(buffer) - LWS_PRE;
if (lws_add_http_header_status(wsi, HTTP_STATUS_UNAUTHORIZED, &p, end))
return 1;
if (lws_add_http_header_by_token(wsi,
WSI_TOKEN_HTTP_WWW_AUTHENTICATE,
(unsigned char *) "Basic realm=\"ttyd\"",
18, &p, end))
return 1;
if (lws_add_http_header_content_length(wsi, 0, &p, end))
return 1;
if (lws_finalize_http_header(wsi, &p, end))
return 1;
if (lws_write(wsi, buffer + LWS_PRE, p - (buffer + LWS_PRE), LWS_WRITE_HTTP_HEADERS) < 0)
return 1;
return -1;
}
int
callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) {
struct pss_http *pss = (struct pss_http *) user;
unsigned char buffer[4096 + LWS_PRE], *p, *end;
char buf[256], name[100], rip[50];
switch (reason) {
case LWS_CALLBACK_HTTP:
// only GET method is allowed
if (!lws_hdr_total_length(wsi, WSI_TOKEN_GET_URI) || len < 1) {
lws_return_http_status(wsi, HTTP_STATUS_BAD_REQUEST, NULL);
return 0;
}
snprintf(pss->path, sizeof(pss->path), "%s", (const char *)in);
lws_get_peer_addresses(wsi, lws_get_socket_fd(wsi), name, sizeof(name), rip, sizeof(rip));
lwsl_notice("HTTP %s - %s (%s)\n", (char *) in, rip, name);
switch (check_auth(wsi)) {
case 0:
break;
case -1:
return 0;
case 1:
default:
return 1;
}
p = buffer + LWS_PRE;
end = p + sizeof(buffer) - LWS_PRE;
if (strncmp(pss->path, "/auth_token.js", 14) == 0) {
size_t n = server->credential != NULL ? sprintf(buf, "var tty_auth_token = '%s';", server->credential) : 0;
if (lws_add_http_header_status(wsi, HTTP_STATUS_OK, &p, end))
return 1;
if (lws_add_http_header_by_token(wsi,
WSI_TOKEN_HTTP_CONTENT_TYPE,
(unsigned char *) "application/javascript",
22, &p, end))
return 1;
if (lws_add_http_header_content_length(wsi, (unsigned long) n, &p, end))
return 1;
if (lws_finalize_http_header(wsi, &p, end))
return 1;
if (lws_write(wsi, buffer + LWS_PRE, p - (buffer + LWS_PRE), LWS_WRITE_HTTP_HEADERS) < 0)
return 1;
if (n > 0) {
pss->buffer = strdup(buf);
pss->len = n;
lws_callback_on_writable(wsi);
}
return 0;
}
if (strcmp(pss->path, "/") != 0) {
lws_return_http_status(wsi, HTTP_STATUS_NOT_FOUND, NULL);
return 0;
}
const char* content_type = "text/html";
if (server->index != NULL) {
int n = lws_serve_http_file(wsi, server->index, content_type, NULL, 0);
if (n < 0 || (n > 0 && lws_http_transaction_completed(wsi)))
return 1;
} else {
if (lws_add_http_header_status(wsi, HTTP_STATUS_OK, &p, end))
return 1;
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE, (const unsigned char *) content_type, 9, &p, end))
return 1;
if (lws_add_http_header_content_length(wsi, (unsigned long) index_html_len, &p, end))
return 1;
if (lws_finalize_http_header(wsi, &p, end))
return 1;
if (lws_write(wsi, buffer + LWS_PRE, p - (buffer + LWS_PRE), LWS_WRITE_HTTP_HEADERS) < 0)
return 1;
pss->buffer = (char *) index_html;
pss->len = index_html_len;
lws_callback_on_writable(wsi);
return 0;
}
break;
case LWS_CALLBACK_HTTP_WRITEABLE:
if (pss->len > 0) {
int n = lws_write_http(wsi, pss->buffer, pss->len);
if (strncmp(pss->path, "/", 1) != 0)
free(pss->buffer);
if (n < pss->len)
return 1;
}
if (lws_http_transaction_completed(wsi))
return -1;
break;
case LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION:
if (!len || (SSL_get_verify_result((SSL *) in) != X509_V_OK)) {
int err = X509_STORE_CTX_get_error((X509_STORE_CTX *) user);
int depth = X509_STORE_CTX_get_error_depth((X509_STORE_CTX *) user);
const char *msg = X509_verify_cert_error_string(err);
lwsl_err("client certificate verification error: %s (%d), depth: %d\n", msg, err, depth);
return 1;
}
break;
default:
break;
}
return 0;
}