int try_upgrade(request_t *req, connection_t *con) { // Does it contain "Upgrade: websocket"? // TODO: Also needs "Connection: Upgrade" // TODO: 'websocket' match is case insensitive. char *upgrade = request_get_header(req, "Upgrade"); if (upgrade == NULL || strcmp(upgrade, "websocket")) { // Not an upgrade. return 0; } char *version = request_get_header(req, "Sec-WebSocket-Version"); if (strcmp(version, "8") && strcmp(version, "13")) { printf("Wrong WebSocket version! %s, expecting 8 or 13.\n", version); return 0; } char iv[] = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; char *key = request_get_header(req, "Sec-WebSocket-Key"); char concat[80]; // TODO: exact length? strcpy(concat, key); strcat(concat, iv); char *hash = (char *) SHA1((unsigned char *)concat, strlen(concat), NULL); BIO *b64 = BIO_new(BIO_f_base64()); BIO *bmem = BIO_new(BIO_s_mem()); BIO_push(b64, bmem); BIO_write(b64, hash, 20); if (BIO_flush(b64) != 1) perror("BIO_flush"); BUF_MEM *bptr; BIO_get_mem_ptr(b64, &bptr); char *hash_enc = malloc(bptr->length); memcpy(hash_enc, bptr->data, bptr->length); hash_enc[bptr->length - 1] = 0; char msg_f[] = "HTTP/1.1 101 Switching Protocols\r\n" "Connection: Upgrade\r\n" "Upgrade: websocket\r\n" "Sec-WebSocket-Accept: %s\r\n\r\n"; // hash_enc is 28 bytes long, replacing '%s'... char *msg = malloc(strlen(msg_f) + (28-2)); sprintf(msg, msg_f, hash_enc); socket_write(con->socket, msg, strlen(msg)); BIO_free_all(b64); con->is_websocket = 1; return 1; }
static int handle_cache(request_t *req, response_t *resp, const struct stat *st, const mod_static_conf_t *conf) { const char *if_mod_since, *if_none_match; char *etag; time_t mtime, req_mtime; int not_modified = 0; char *buf; char *cache_control; mtime = st->st_mtime; if_mod_since = request_get_header(req, "if-modified-since"); if (if_mod_since != NULL && parse_http_date(if_mod_since, &req_mtime) == 0 && req_mtime == mtime) { debug("Resource not modified"); not_modified = 1; } buf = response_alloc(resp, 32); format_http_date(&mtime, buf, 32); response_set_header(resp, "Last-Modified", buf); if (conf->enable_etag) { etag = generate_etag(st); if (not_modified) { if_none_match = request_get_header(req, "if-none-match"); if (if_none_match == NULL || strcmp(etag, if_none_match) != 0) { not_modified = 0; } } response_set_header(resp, "ETag", etag); } if (conf->expire_hours >= 0) { buf = response_alloc(resp, 32); mtime += conf->expire_hours * 3600; format_http_date(&mtime, buf, 32); response_set_header(resp, "Expires", buf); cache_control = response_alloc(resp, 20); snprintf(cache_control, 20, "max-age=%d", conf->expire_hours * 3600); } else { cache_control = "no-cache"; } response_set_header(resp, "Cache-Control", cache_control); return not_modified; }
/* * Return values: * 0: valid range request * 1: range not satisfiable (should return 416) * -1: syntactically invalid range (ignore, return full content) */ static int handle_range(request_t *req, response_t *resp, size_t *offset, size_t *size) { const char *range_spec; char buf[100], *pos; size_t len, total_size = *size, off, sz, end; int idx; range_spec = request_get_header(req, "range"); if (range_spec == NULL) { return -1; } len = strlen(range_spec); if (len < 8) { return -1; } if (strstr(range_spec, "bytes=") != range_spec) { error("Only byte ranges are supported(error range:%s)", range_spec); return -1; } strncpy(buf, range_spec + 6, 100); len = strlen(buf); if (index(buf, ',') != NULL) { error("Multiple ranges are not supported."); return -1; } pos = index(buf, '-'); if (pos == NULL) { error("Invalid range spec: %s.", range_spec); return -1; } idx = pos - buf; if (idx == 0) { sz = atol(buf + 1); end = total_size; off = total_size - sz; } else if (idx == len - 1) { buf[idx] = '\0'; off = atol(buf); end = total_size; sz = total_size - off; } else { buf[idx] = '\0'; off = atol(buf); end = atol(buf + idx + 1); sz = end - off + 1; } if (end < off) return -1; if (off >= total_size || sz > total_size) return 1; response_set_header_printf(resp, "Content-Range", "bytes %ld-%ld/%ld", off, off + sz - 1, total_size); *offset = off; *size = sz; return 0; }