Example #1
0
TEST_END

TEST_START(at_kv)
{
    clax_kv_list_t list;
    clax_kv_list_item_t *item;

    clax_kv_list_init(&list);

    ASSERT(clax_kv_list_at(&list, 0) == NULL);
    ASSERT(clax_kv_list_at(&list, 10) == NULL);

    clax_kv_list_push(&list, "foo", "bar");
    clax_kv_list_push(&list, "bar", "baz");
    clax_kv_list_push(&list, "bar", "zab");

    item = clax_kv_list_at(&list, 0);
    ASSERT_STR_EQ(item->key, "foo");
    ASSERT_STR_EQ(item->val, "bar");

    item = clax_kv_list_at(&list, 1);
    ASSERT_STR_EQ(item->key, "bar");
    ASSERT_STR_EQ(item->val, "baz");

    item = clax_kv_list_at(&list, 2);
    ASSERT_STR_EQ(item->key, "bar");
    ASSERT_STR_EQ(item->val, "zab");

    ASSERT(clax_kv_list_at(&list, 3) == NULL);

    clax_kv_list_free(&list);
}
Example #2
0
void clax_dispatch_not_authorized(clax_ctx_t *clax_ctx, clax_http_request_t *req, clax_http_response_t *res)
{
    res->status_code = 401;
    clax_kv_list_push(&res->headers, "Content-Type", "text/plain");
    clax_kv_list_push(&res->headers, "WWW-Authenticate", "Basic realm=\"clax\"");
    clax_big_buf_append_str(&res->body, "Authorization required");
}
Example #3
0
TEST_END

TEST_START(finds_all_kv)
{
    size_t start = 0;
    clax_kv_list_t list;

    clax_kv_list_init(&list);

    ASSERT(clax_kv_list_find_all(&list, "foo", &start) == NULL);
    ASSERT_EQ(start, 0);

    start = 100;
    ASSERT(clax_kv_list_find_all(&list, "foo", &start) == NULL);
    ASSERT_EQ(start, 100);

    clax_kv_list_push(&list, "foo", "bar");
    clax_kv_list_push(&list, "bar", "baz");
    clax_kv_list_push(&list, "bar", "zab");

    start = 0;
    ASSERT_STR_EQ(clax_kv_list_find_all(&list, "foo", &start), "bar");
    ASSERT_EQ(start, 1);
    ASSERT(clax_kv_list_find_all(&list, "foo", &start) == NULL);
    ASSERT(clax_kv_list_find_all(&list, "foo", &start) == NULL);

    start = 0;
    ASSERT_STR_EQ(clax_kv_list_find_all(&list, "bar", &start), "baz");
    ASSERT_STR_EQ(clax_kv_list_find_all(&list, "bar", &start), "zab");
    ASSERT(clax_kv_list_find_all(&list, "bar", &start) == NULL);
    ASSERT(clax_kv_list_find_all(&list, "bar", &start) == NULL);

    clax_kv_list_free(&list);
}
Example #4
0
TEST_END

TEST_START(pushes_kv)
{
    clax_kv_list_t list;

    clax_kv_list_init(&list);

    clax_kv_list_push(&list, "foo", "bar");
    ASSERT_EQ(list.size, 1);

    clax_kv_list_push(&list, "bar", "baz");
    ASSERT_EQ(list.size, 2);

    clax_kv_list_push(&list, NULL, NULL);
    ASSERT_EQ(list.size, 3);

    clax_kv_list_free(&list);
}
Example #5
0
void clax_dispatch_bad_request(clax_ctx_t *clax_ctx, clax_http_request_t *req, clax_http_response_t *res, char *msg)
{
    char *p = msg;

    if (p == NULL) {
        p = "Bad Request";
    }

    res->status_code = 400;
    clax_kv_list_push(&res->headers, "Content-Type", "text/plain");
    clax_big_buf_append_str(&res->body, p);
}
Example #6
0
void clax_dispatch_system_error(clax_ctx_t *clax_ctx, clax_http_request_t *req, clax_http_response_t *res, char *msg)
{
    char *p = msg;

    if (p == NULL) {
        p = "System error";
    }

    clax_kv_list_push(&res->headers, "Content-Type", "text/plain");
    res->status_code = 500;
    clax_big_buf_append_str(&res->body, p);
}
Example #7
0
TEST_END

TEST_START(finds_kv)
{
    clax_kv_list_t list;

    clax_kv_list_init(&list);

    ASSERT(clax_kv_list_find(&list, "foo") == NULL);

    clax_kv_list_push(&list, "foo", "bar");
    clax_kv_list_push(&list, "bar", "baz");
    clax_kv_list_push(&list, "bar", "zab");

    ASSERT_STR_EQ(clax_kv_list_find(&list, "foo"), "bar");
    ASSERT_STR_EQ(clax_kv_list_find(&list, "bar"), "baz");
    ASSERT_STR_EQ(clax_kv_list_find(&list, "bar"), "baz");

    ASSERT(clax_kv_list_find(&list, "unknown") == NULL);

    clax_kv_list_free(&list);
}
Example #8
0
TEST_END

TEST_START(iter_kv)
{
    clax_kv_list_t list;
    clax_kv_list_item_t *item;
    size_t iter = 0;

    clax_kv_list_init(&list);

    ASSERT(clax_kv_list_next(&list, &iter) == NULL);
    ASSERT(clax_kv_list_next(&list, &iter) == NULL);

    clax_kv_list_push(&list, "foo", "bar");
    clax_kv_list_push(&list, "bar", "baz");
    clax_kv_list_push(&list, "bar", "zab");

    item = clax_kv_list_next(&list, &iter);
    ASSERT_EQ(iter, 1);
    ASSERT_STR_EQ(item->key, "foo");
    ASSERT_STR_EQ(item->val, "bar");

    item = clax_kv_list_next(&list, &iter);
    ASSERT_EQ(iter, 2);
    ASSERT_STR_EQ(item->key, "bar");
    ASSERT_STR_EQ(item->val, "baz");

    item = clax_kv_list_next(&list, &iter);
    ASSERT_EQ(iter, 3);
    ASSERT_STR_EQ(item->key, "bar");
    ASSERT_STR_EQ(item->val, "zab");

    ASSERT(clax_kv_list_next(&list, &iter) == NULL);
    ASSERT(clax_kv_list_next(&list, &iter) == NULL);

    clax_kv_list_free(&list);
}
Example #9
0
void clax_dispatch_command(clax_ctx_t *clax_ctx, clax_http_request_t *req, clax_http_response_t *res)
{
    memset(&command_ctx, 0, sizeof(command_ctx_t));

    char *command = clax_kv_list_find(&req->body_params, "command");
    if (!command || !strlen(command)) {
        clax_dispatch_bad_request(clax_ctx, req, res);
        return;
    }

    strncpy(command_ctx.command, command, sizeof_struct_member(command_ctx_t, command));

    char *timeout = clax_kv_list_find(&req->body_params, "timeout");
    if (timeout && strlen(timeout)) {
        command_ctx.timeout = atoi(timeout);
    }

    pid_t pid = clax_command_start(&command_ctx);
    if (pid <= 0) {
        clax_dispatch_system_error(clax_ctx, req, res);
        return;
    }

    res->status_code = 200;

    clax_kv_list_push(&res->headers, "Transfer-Encoding", "chunked");

    char buf_pid[15];
    snprintf(buf_pid, sizeof(buf_pid), "%d", pid);

    clax_kv_list_push(&res->headers, "Trailer", "X-Clax-Exit");
    clax_kv_list_push(&res->headers, "X-Clax-PID", buf_pid);

    res->body_cb_ctx = &command_ctx;
    res->body_cb = clax_command_read_cb;
}
Example #10
0
void clax_dispatch_download(clax_ctx_t *clax_ctx, clax_http_request_t *req, clax_http_response_t *res)
{
    char *file = req->path_info + strlen("/tree/");

    char buf[255];
    char base_buf[255];
    char last_modified_buf[30];
    struct stat st;
    struct tm last_modified_time;
    struct tm *last_modified_time_p;

    if (stat(file, &st) != 0 || !(st.st_mode & S_IFREG)) {
        clax_dispatch_not_found(clax_ctx, req, res);
        return;
    }

    unsigned long crc32 = clax_crc32_calc_file(file);
    char crc32_hex[9] = {0};
    snprintf(crc32_hex, sizeof(crc32_hex), "%lx", crc32);

    FILE *fh = fopen(file, "rb");

    if (fh == NULL) {
        clax_dispatch_not_found(clax_ctx, req, res);
        return;
    }

    snprintf(buf, sizeof(buf), "%d", (int)st.st_size);

    char *base = basename(file);
    strcpy(base_buf, "attachment; filename=\"");
    strcat(base_buf, base);
    strcat(base_buf, "\"");

    res->status_code = 200;
    clax_kv_list_push(&res->headers, "Content-Type", "application/octet-stream");
    clax_kv_list_push(&res->headers, "Content-Disposition", base_buf);
    clax_kv_list_push(&res->headers, "Pragma", "no-cache");
    clax_kv_list_push(&res->headers, "Content-Length", buf);

    last_modified_time_p = gmtime_r(&st.st_mtime, &last_modified_time);

    strftime(last_modified_buf, sizeof(last_modified_buf), "%a, %d %b %Y %H:%M:%S GMT", last_modified_time_p);
    clax_kv_list_push(&res->headers, "Last-Modified", last_modified_buf);

    clax_kv_list_push(&res->headers, "X-Clax-CRC32", crc32_hex);

    if (req->method == HTTP_GET)
        res->body_fh = fh;
    else
        fclose(fh);
}
Example #11
0
void clax_dispatch_delete(clax_ctx_t *clax_ctx, clax_http_request_t *req, clax_http_response_t *res)
{
    char *file = req->path_info + strlen("/tree/");
    struct stat st;

    if (stat(file, &st) != 0 || !(st.st_mode & S_IFREG)) {
        clax_dispatch_not_found(clax_ctx, req, res);
        return;
    }

    int ret = unlink(file);

    if (ret == 0) {
        res->status_code = 200;
        clax_kv_list_push(&res->headers, "Content-Type", "application/json");
        clax_big_buf_append_str(&res->body, "{\"message\":\"ok\"}");
    }
    else {
        clax_dispatch_system_error(clax_ctx, req, res);
        return;
    }
}
Example #12
0
void clax_dispatch_not_found(clax_ctx_t *clax_ctx, clax_http_request_t *req, clax_http_response_t *res)
{
    clax_kv_list_push(&res->headers, "Content-Type", "text/plain");
    res->status_code = 404;
    clax_big_buf_append_str(&res->body, "Not found");
}
Example #13
0
void clax_dispatch_upload(clax_ctx_t *clax_ctx, clax_http_request_t *req, clax_http_response_t *res)
{
    char *subdir = req->path_info + strlen("/tree/");

    if (strlen(subdir)) {
        struct stat info;

        if (stat(subdir, &info) == 0 && info.st_mode & S_IFDIR) {
        } else {
            clax_log("Output directory '%s' does not exist", subdir);

            clax_dispatch_bad_request(clax_ctx, req, res);
            return;
        }
    }

    if (req->continue_expected) {
        return;
    }

    if (strlen(req->multipart_boundary)) {
        int i;
        for (i = 0; i < req->multiparts.size; i++) {
            clax_http_multipart_t *multipart = clax_http_multipart_list_at(&req->multiparts, i);

            const char *content_disposition = clax_kv_list_find(&multipart->headers, "Content-Disposition");
            if (!content_disposition)
                continue;

            char prefix[] = "form-data; ";
            if (strncmp(content_disposition, prefix, strlen(prefix)) != 0)
                continue;

            const char *kv = content_disposition + strlen(prefix);
            size_t name_len;
            size_t filename_len;
            const char *name = clax_http_extract_kv(kv, "name", &name_len);
            const char *filename = clax_http_extract_kv(kv, "filename", &filename_len);

            if (!name || !filename || (strncmp(name, "file", name_len) != 0))
                continue;

            char *new_name = clax_kv_list_find(&req->query_params, "name");
            char *crc32 = clax_kv_list_find(&req->query_params, "crc");
            char *time = clax_kv_list_find(&req->query_params, "time");

            if (crc32 && strlen(crc32) != 8) {
                clax_dispatch_bad_request(clax_ctx, req, res);
                return;
            }

            char *fpath;

            if (new_name && strlen(new_name)) {
                fpath = clax_strjoin("/", subdir, new_name, NULL);
            }
            else {
                char *p = clax_strndup(filename, filename_len);
                fpath = clax_strjoin("/", subdir, p, NULL);
                free(p);
            }

            clax_san_path(fpath);

            int ret = clax_big_buf_write_file(&multipart->bbuf, fpath);

            if (ret < 0) {
                clax_log("Saving file failed: %s\n", fpath);
                clax_dispatch_system_error(clax_ctx, req, res);
            }
            else {
                if (crc32 && strlen(crc32)) {
                    unsigned long got_crc32 = clax_htol(crc32);

                    int fd = open(fpath, O_RDONLY);
                    unsigned long exp_crc32 = clax_crc32_calc_fd(fd);
                    close(fd);

                    if (got_crc32 != exp_crc32) {
                        clax_log("CRC mismatch %u != %u (%s)", exp_crc32, got_crc32, crc32);
                        clax_dispatch_bad_request(clax_ctx, req, res);

                        remove(fpath);
                        free(fpath);

                        return;
                    } else {
                        clax_log("CRC ok %u != %u (%s)", exp_crc32, got_crc32, crc32);
                    }
                }

                if (time && strlen(time)) {
                    int mtime = atol(time);

                    struct utimbuf t;
                    t.actime = mtime;
                    t.modtime = mtime;
                    int ok = utime(fpath, &t);

                    if (ok < 0)
                        clax_log("utime on file '%s' failed: %s", fpath, strerror(errno));
                }

                res->status_code = 200;
                clax_kv_list_push(&res->headers, "Content-Type", "application/json");

                clax_big_buf_append_str(&res->body, "{\"message\":\"ok\"}");
            }

            free(fpath);

            break;
        }
    }

    if (!res->status_code) {
        clax_dispatch_bad_request(clax_ctx, req, res);
    }
}
Example #14
0
void clax_dispatch_system_error(clax_ctx_t *clax_ctx, clax_http_request_t *req, clax_http_response_t *res)
{
    clax_kv_list_push(&res->headers, "Content-Type", "text/plain");
    res->status_code = 500;
    clax_big_buf_append_str(&res->body, "System error");
}
Example #15
0
void clax_dispatch_success(clax_ctx_t *clax_ctx, clax_http_request_t *req, clax_http_response_t *res)
{
    clax_kv_list_push(&res->headers, "Content-Type", "application/json");
    res->status_code = 200;
    clax_big_buf_append_str(&res->body, "{\"message\":\"ok\"}");
}
Example #16
0
void clax_dispatch_method_not_allowed(clax_ctx_t *clax_ctx, clax_http_request_t *req, clax_http_response_t *res)
{
    clax_kv_list_push(&res->headers, "Content-Type", "text/plain");
    res->status_code = 405;
    clax_big_buf_append_str(&res->body, "Method not allowed");
}
Example #17
0
void clax_dispatch_bad_gateway(clax_ctx_t *clax_ctx, clax_http_request_t *req, clax_http_response_t *res)
{
    clax_kv_list_push(&res->headers, "Content-Type", "text/plain");
    res->status_code = 502;
    clax_big_buf_append_str(&res->body, "Bad Gateway");
}