Beispiel #1
0
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;
}
Beispiel #2
0
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;
}
Beispiel #3
0
/*
 * 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;
}