Ejemplo n.º 1
0
int connection_proxy_req_parse(Connection *conn)
{
    int rc = 0;
    Host *target_host = conn->req->target_host;
    Backend *req_action = conn->req->action;

    check_debug(!IOBuf_closed(conn->iob), "Client closed, goodbye.");

    rc = Connection_read_header(conn, conn->req);

    check_debug(rc > 0, "Failed to read another header.");
    error_unless(Request_is_http(conn->req), conn, 400,
            "Someone tried to change the protocol on us from HTTP.");

    Backend *found = Host_match_backend(target_host, Request_path(conn->req), NULL);
    error_unless(found, conn, 404, 
            "Handler not found: %s", bdata(Request_path(conn->req)));

    // break out of PROXY if the actions don't match
    if(found != req_action) {
        Request_set_action(conn->req, found);
        return Connection_backend_event(found, conn);
    } else {
        return HTTP_REQ;
    }

    error_response(conn, 500, "Invalid code branch, tell Zed.");
error:
    return REMOTE_CLOSE;
}
Ejemplo n.º 2
0
static inline int stream_to_disk(IOBuf *iob, int content_len, int tmpfd)
{
    char *data = NULL;
    int avail = 0;

    debug("max content length: %d, content_len: %d", MAX_CONTENT_LENGTH, content_len);

    IOBuf_resize(iob, MAX_CONTENT_LENGTH); // give us a good buffer size

    while(content_len > 0) {
        data = IOBuf_read_some(iob, &avail);
        check(!IOBuf_closed(iob), "Closed while reading from IOBuf.");
        content_len -= avail;
        check(write(tmpfd, data, avail) == avail, "Failed to write requested amount to tempfile: %d", avail);

        check(IOBuf_read_commit(iob, avail) != -1, "Final commit failed streaming to disk.");
    }

    check(content_len == 0, "Failed to write everything to the large upload tmpfile.");

    return 0;

error:
    return -1;
}
Ejemplo n.º 3
0
char *test_IOBuf_send_operations() 
{
    Connection *conn = fake_conn("/dev/null", O_WRONLY);
    mu_assert(conn != NULL, "Failed to allocate buf.");
    IOBuf *buf = conn->iob;
    mu_assert(Register_fd_exists(IOBuf_fd(buf)) != NULL, "Damn fd isn't registered.");

    int rc = IOBuf_send(buf, "012345789", 10);
    mu_assert(!IOBuf_closed(buf), "Should not be closed.");
    mu_assert(rc == 10, "Should have sent 10 bytes.");

    fdclose(IOBuf_fd(buf));
    rc = IOBuf_send(buf, "012345789", 10);
    mu_assert(IOBuf_closed(buf), "Should be closed.");
    mu_assert(rc == -1, "Should send nothing.");

    fake_conn_close(conn);

    return NULL;
}
Ejemplo n.º 4
0
/**
 * Does a non-blocking read and either reads in the amount you requested
 * with "need" or less so you can try again.  It sets out_len to what is
 * available (<= need) so you can decide after that.  You can keep attempting
 * to read more and more (up to buf->len) and you'll get the same start point
 * each time.
 *
 * Once you're done with the data you've been trying to read, you use IOBuf_read_commit
 * to commit the "need" amount and then start doing new reads.
 *
 * Internally this works like a "half open ring buffer" and it tries to greedily
 * read as much as possible without blocking or copying.
 *
 * To just get as much as possible, use the IOBuf_read_some macro.
 */
char *IOBuf_read(IOBuf *buf, int need, int *out_len)
{
    int rc = 0;
    assert(buf->cur + buf->avail <= buf->len && 
            "Buffer math off, cur+avail can't be more than > len.");
    assert(buf->cur >= 0 && "Buffer cur can't be < 0");
    assert(buf->avail >= 0 && "Buffer avail can't be < 0");
    assert(need <= buf->len && "Request for more than possible in the buffer.");

    if(IOBuf_closed(buf)) {
        if(buf->avail > 0) {
            *out_len = buf->avail;
        } else {
            *out_len = 0;
            return NULL;
        }
    } else if(buf->avail < need) {
        if(buf->cur > 0 && IOBuf_compact_needed(buf, need)) {
            IOBuf_compact(buf);
        }
        rc = buf->recv(buf, IOBuf_read_point(buf), IOBuf_remaining(buf));

        if(rc <= 0) {
            debug("Socket was closed, will return only what's available: %d", buf->avail);
            buf->closed = 1;
        } else {
            buf->avail = buf->avail + rc;
        }

        if(buf->avail < need) {
            // less than expected
            *out_len = buf->avail;
        } else {
            // more than expected
            *out_len = need;
        }
    } else if(buf->avail >= need) {
        *out_len = need;
    } else {
        sentinel("Invalid branch processing buffer, Tell Zed.");
    }

    return IOBuf_start(buf);

error:
    return NULL;
}
Ejemplo n.º 5
0
/**
 * Reads the entire amount requested into the IOBuf (as long as there's
 * space to hold it) and then commits that read in one shot.
 */
char *IOBuf_read_all(IOBuf *buf, int len, int retries)
{
    int nread = 0;
    int attempts = 0;

    check_debug(!IOBuf_closed(buf), "Closed when attempting to read from buffer.");

    if(len > buf->len) {
        // temporarily grow the buffer
        IOBuf_resize(buf, len);
    }

    char *data = IOBuf_read(buf, len, &nread);

    debug("INITIAL READ: len: %d, nread: %d", len, nread);
    for(attempts = 0; nread < len; attempts++) {
        data = IOBuf_read(buf, len, &nread);

        check_debug(data, "Read error from socket.");
        assert(nread <= len && "Invalid nread size (too much) on IOBuf read.");

        if(nread == len) {
            break;
        } else {
            fdwait(buf->fd, 'r');
        }
    }
   
    debug("ATTEMPTS: %d, RETRIES: %d", attempts, retries);

    if(attempts > retries) {
        log_warn("Read of %d length attempted %d times which is over %d retry limit..", len, attempts, retries);
    }

    check(IOBuf_read_commit(buf, len) != -1, "Final commit failed of read_all.");
    return data;

error:
    buf->closed = 1;
    return NULL;
}
Ejemplo n.º 6
0
int Connection_read_header(Connection *conn, Request *req)
{
    char *data = IOBuf_start(conn->iob);
    int avail = IOBuf_avail(conn->iob);
    int rc = 0;
    size_t nparsed = 0;
    int tries = 0;

    Request_start(req);

    for(tries = 0; rc == 0 && tries < CLIENT_READ_RETRIES; tries++) {
        if(avail > 0) {
            rc = Request_parse(req, data, avail, &nparsed);
        }

        if(rc == 0) {
            data = IOBuf_read_some(conn->iob, &avail);
            check_debug(!IOBuf_closed(conn->iob), "Client closed during read.");
        }
    }

    error_unless(tries < CLIENT_READ_RETRIES, conn, 
            400, "Too many small packet read attempts.");
    error_unless(rc == 1, conn, 400, "Error parsing request.");

    // add the x-forwarded-for header
    Request_set(conn->req, bstrcpy(&HTTP_X_FORWARDED_FOR),
            blk2bstr(conn->remote, IPADDR_SIZE), 1);

    check_should_close(conn, conn->req);

    return nparsed;

error:
    return -1;

}
Ejemplo n.º 7
0
int Connection_read_wspacket(Connection *conn)
{
    bstring payload=NULL;

    uint8_t *dataU=NULL;
    char *data = IOBuf_start(conn->iob);
    int avail = IOBuf_avail(conn->iob);
    int64_t packet_length=-1;
    int smaller_packet_length;
    int header_length;
    char key[4];
    int i;
    int data_length;
    int tries = 0;
    int rc=0;
    int fin;
    int inprogFlags=0;
    int isControl;
    int flags;

again:
    dataU=NULL;
    data = IOBuf_start(conn->iob);
    avail = IOBuf_avail(conn->iob);
    packet_length=-1;
    smaller_packet_length=0;
    header_length=0;
    i=0;
    data_length=0;
    tries = 0;
    rc=0;
    fin=0;

    for(tries = 0; packet_length == -1 && tries < 8*CLIENT_READ_RETRIES; tries++) {
        if(avail > 0) {
            packet_length = Websocket_packet_length((uint8_t *)data, avail);
        }

        if(packet_length == -1) {
            data = IOBuf_read_some(conn->iob, &avail);
            check_debug(!IOBuf_closed(conn->iob), "Client closed during read.");
        }
    }
    check(packet_length > 0,"Error receiving websocket packet header.")

    check_debug(packet_length <= INT_MAX,"Websocket packet longer than MAXINT.");
    /* TODO properly terminate WS connection */

    smaller_packet_length = (int)packet_length;
    
    /* TODO check for maximum length */

    header_length=Websocket_header_length((uint8_t *) data, avail);
    data_length=smaller_packet_length-header_length;
    dataU = (uint8_t *)IOBuf_read_all(conn->iob,header_length,8*CLIENT_READ_RETRIES);
    memcpy(key,dataU+header_length-4,4);

    flags=dataU[0];
    if (payload==NULL) {
        inprogFlags=flags;
    }
    

    fin=(WS_fin(dataU));
    isControl=(WS_is_control(dataU));

{
    const char *error=WS_validate_packet(dataU,payload!=NULL);
    check(error==NULL,"%s",error);
}

    dataU = (uint8_t *)IOBuf_read_all(conn->iob,data_length, 8*CLIENT_READ_RETRIES);
    check(dataU != NULL, "Client closed the connection during websocket packet.");

    for(i=0;i<data_length;++i) {
        dataU[i]^=key[i%4];
    }

    if(isControl) /* Control frames get sent right-away */
    {
            Request_set(conn->req,bfromcstr("FLAGS"),bformat("0x%X",flags|0x80),1);
            rc = Connection_send_to_handler(conn, conn->handler, (void *)dataU,data_length);
            check_debug(rc == 0, "Failed to deliver to the handler.");
    }
    else {
        if(fin) {
            Request_set(conn->req,bfromcstr("FLAGS"),bformat("0x%X",inprogFlags|0x80),1);
        }
        if (payload == NULL) {
            if (fin) {
                rc = Connection_send_to_handler(conn, conn->handler, (void *)dataU,data_length);
                check_debug(rc == 0, "Failed to deliver to the handler.");
            }
            else {
                payload = blk2bstr(dataU,data_length);
                check(payload != NULL,"Allocation failed");
            }
        } else {
            check(BSTR_OK == bcatblk(payload,dataU,data_length), "Concatenation failed");
            if (fin) {
                rc = Connection_send_to_handler(conn, conn->handler, bdata(payload),blength(payload));
                check_debug(rc == 0, "Failed to deliver to the handler.");
                bdestroy(payload);
                payload=NULL;
            }
        }
    }
    if (payload != NULL) {
        goto again;
    }


    return packet_length;

error:
    bdestroy(payload);
    return -1;

}
Ejemplo n.º 8
0
/**
 * Reads the entire amount requested into the IOBuf (as long as there's
 * space to hold it) and then commits that read in one shot.
 */
char *IOBuf_read_all(IOBuf *buf, int len, int retries)
{
    int nread = 0;
    int attempts = 0;

    check_debug(!IOBuf_closed(buf), "Closed when attempting to read from buffer.");

    if(len > buf->len) {
        // temporarily grow the buffer
        IOBuf_resize(buf, len);
    }

    char *data = IOBuf_read(buf, len, &nread);

    debug("INITIAL READ: len: %d, nread: %d", len, nread);
    for(attempts = 0; nread < len; attempts++) {
        data = IOBuf_read(buf, len, &nread);

        check_debug(data, "Read error from socket.");
        assert(nread <= len && "Invalid nread size (too much) on IOBuf read.");

        if(nread == len) {
            log_warn("recive all data");
            break;
        } 
        else if(IOBuf_closed(buf)){//register closed or socket error
            if(buf->buf) free(buf->buf);
            buf->buf = strdup("upload=false&info='connection error'");
            buf->len = strlen(buf->buf);
            buf->avail = buf->len;
            buf->cur = buf->len;
            
            log_warn("connection error");
            len = buf->len;
            goto error;
            
            /*if(buf->buf) free(buf->buf);
            buf->buf = NULL; 
            buf->len = 0; 
            buf->avail = 0;
            buf->cur = 0;
            log_warn("connection error");
            goto error; */
        }
        else {
            fdwait(buf->fd, 'r');
        }
    }
   
    debug("ATTEMPTS: %d, RETRIES: %d", attempts, retries);

    if(attempts > retries) {
        log_warn("Read of %d length attempted %d times which is over %d retry limit..", len, attempts, retries);
    }

    check(IOBuf_read_commit(buf, len) != -1, "Final commit failed of read_all.");
    return data;

error:
    buf->closed = 1;
    return NULL;
}
Ejemplo n.º 9
0
int Upload_stream(Connection *conn, Handler *handler, int content_len)
{
    char *data = NULL;
    int avail = 0;
    int offset = 0;
    int first_chunk = 1;
    int rc;
    hash_t *altheaders = NULL;
    bstring offsetstr;

    debug("max content length: %d, content_len: %d", MAX_CONTENT_LENGTH, content_len);

    IOBuf_resize(conn->iob, MAX_CONTENT_LENGTH); // give us a good buffer size

    while(content_len > 0) {
        if(first_chunk) {
            // read whatever's there
            data = IOBuf_read_some(conn->iob, &avail);
        } else if(conn->sendCredits > 0) {
            // read up to credits
            data = IOBuf_read(conn->iob, conn->sendCredits < content_len ? conn->sendCredits : content_len, &avail);
            conn->sendCredits -= avail;
        } else {
            // sleep until we have credits
            tasksleep(&conn->uploadRendez);
            continue;
        }

        check(!IOBuf_closed(conn->iob), "Closed while reading from IOBuf.");
        content_len -= avail;

        offsetstr = bformat("%d", offset);

        if(first_chunk) {
            Request_set(conn->req, &UPLOAD_STREAM, offsetstr, 1);
            if(content_len == 0) {
                Request_set(conn->req, &UPLOAD_STREAM_DONE, bfromcstr("1"), 1);
            }
        } else {
            altheaders = hash_create(2, (hash_comp_t)bstrcmp, bstr_hash_fun);
            add_to_hash(altheaders, &UPLOAD_STREAM, offsetstr);
            if(content_len == 0) {
                add_to_hash(altheaders, &UPLOAD_STREAM_DONE, bfromcstr("1"));
            }
        }

        rc = Connection_send_to_handler(conn, handler, data, avail, altheaders);
        check_debug(rc == 0, "Failed to deliver to the handler.");

        if(altheaders != NULL) {
            hash_free_nodes(altheaders);
            hash_destroy(altheaders);
            altheaders = NULL;
        }

        check(IOBuf_read_commit(conn->iob, avail) != -1, "Commit failed while streaming.");

        first_chunk = 0;
        offset += avail;
    }

    check(content_len == 0, "Failed to write everything to the large upload tmpfile.");

    return 0;

error:
    return -1;
}