Example #1
0
static int getattr_user(SeafileSession *seaf, const char *user, struct stat *stbuf)
{
    SearpcClient *client;
    CcnetEmailUser *emailuser;

    client = ccnet_create_pooled_rpc_client (seaf->client_pool,
                                             NULL,
                                             "ccnet-threaded-rpcserver");
    if (!client) {
        seaf_warning ("Failed to alloc rpc client.\n");
        return -ENOMEM;
    }

    emailuser = get_user_from_ccnet (client, user);
    if (!emailuser) {
        ccnet_rpc_client_free (client);
        return -ENOENT;
    }
    g_object_unref (emailuser);
    ccnet_rpc_client_free (client);

    stbuf->st_mode = S_IFDIR | 0755;
    stbuf->st_nlink = 2;
    stbuf->st_size = 4096;

    return 0;
}
Example #2
0
static int readdir_user(SeafileSession *seaf, const char *user,
                        void *buf, fuse_fill_dir_t filler, off_t offset,
                        struct fuse_file_info *info)
{
    SearpcClient *client;
    CcnetEmailUser *emailuser;
    GList *list = NULL, *p;
    GString *name;

    client = ccnet_create_pooled_rpc_client (seaf->client_pool,
                                             NULL,
                                             "ccnet-threaded-rpcserver");
    if (!client) {
        seaf_warning ("Failed to alloc rpc client.\n");
        return -ENOMEM;
    }

    emailuser = get_user_from_ccnet (client, user);
    if (!emailuser) {
        ccnet_rpc_client_free (client);
        return -ENOENT;
    }
    g_object_unref (emailuser);
    ccnet_rpc_client_free (client);

    list = seaf_repo_manager_get_repos_by_owner (seaf->repo_mgr, user);
    if (!list)
        return 0;

    for (p = list; p; p = p->next) {
        SeafRepo *repo = (SeafRepo *)p->data;

        /* Don't list virtual repos. */
        if (seaf_repo_manager_is_virtual_repo(seaf->repo_mgr, repo->id)) {
            seaf_repo_unref (repo);
            continue;
        }
		
		//skip the encrypted repo
		if(repo -> encrypted)
			continue;
		
        char *clean_repo_name = replace_slash (repo->name);

        name = g_string_new ("");
        g_string_printf (name, "%s_%s", repo->id, clean_repo_name);
        filler(buf, name->str, NULL, 0);
        g_string_free (name, TRUE);
        g_free (clean_repo_name);

        seaf_repo_unref (repo);
    }

    g_list_free (list);

    return 0;
}
Example #3
0
static int
handle_auth_req_content_cb (char *content, int clen, void *cbarg)
{
    BlockTxServer *server = cbarg;
    char *session_token = content;
    SearpcClient *client = NULL;
    char repo_id[37];
    SeafRepo *repo;

    if (session_token[clen - 1] != '\0') {
        seaf_warning ("Invalid session token format.\n");
        send_auth_response (server, STATUS_BAD_REQUEST);
        return -1;
    }

    client = ccnet_create_pooled_rpc_client (seaf->client_pool,
                                             NULL,
                                             "ccnet-rpcserver");
    if (!client) {
        seaf_warning ("Failed to create rpc client.\n");
        send_auth_response (server, STATUS_INTERNAL_SERVER_ERROR);
        return -1;
    }

    if (seaf_token_manager_verify_token (seaf->token_mgr, client, NULL,
                                         session_token, repo_id) < 0) {
        seaf_warning ("Session token check failed.\n");
        send_auth_response (server, STATUS_ACCESS_DENIED);
        ccnet_rpc_client_free (client);
        return -1;
    }

    ccnet_rpc_client_free (client);

    repo = seaf_repo_manager_get_repo (seaf->repo_mgr, repo_id);
    if (!repo) {
        seaf_warning ("Failed to get repo %.8s.\n", repo_id);
        return -1;
    }
    memcpy (server->store_id, repo->store_id, 36);
    server->repo_version = repo->version;
    seaf_repo_unref (repo);

    if (send_auth_response (server, STATUS_OK) < 0)
        return -1;

    seaf_debug ("recv_state set to HEADER.\n");

    server->parser.content_cb = handle_block_header_content_cb;
    server->recv_state = RECV_STATE_HEADER;

    return 0;
}
Example #4
0
static int readdir_root(SeafileSession *seaf,
                        void *buf, fuse_fill_dir_t filler, off_t offset,
                        struct fuse_file_info *info)
{
    SearpcClient *client = NULL;
    GList *users, *p;
    CcnetEmailUser *user;
    const char *email;
    GHashTable *user_hash;
    int dummy;

    client = ccnet_create_pooled_rpc_client (seaf->client_pool,
                                             NULL,
                                             "ccnet-threaded-rpcserver");
    if (!client) {
        seaf_warning ("Failed to alloc rpc client.\n");
        return -ENOMEM;
    }

    user_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);

    users = get_users_from_ccnet (client, "DB");
    for (p = users; p; p = p->next) {
        user = p->data;
        email = ccnet_email_user_get_email (user);
        g_hash_table_insert (user_hash, g_strdup(email), &dummy);
        g_object_unref (user);
    }
    g_list_free (users);

    users = get_users_from_ccnet (client, "LDAP");
    for (p = users; p; p = p->next) {
        user = p->data;
        email = ccnet_email_user_get_email (user);
        g_hash_table_insert (user_hash, g_strdup(email), &dummy);
        g_object_unref (user);
    }
    g_list_free (users);

    users = g_hash_table_get_keys (user_hash);
    for (p = users; p; p = p->next) {
        email = p->data;
        filler (buf, email, NULL, 0);
    }
    g_list_free (users);

    g_hash_table_destroy (user_hash);
    ccnet_rpc_client_free (client);

    return 0;
}
Example #5
0
static int
process_session_key (BlockTxServer *server, unsigned char *enc_session_key)
{
    char *enc_key_b64 = NULL, *key_b64 = NULL;
    unsigned char *session_key = NULL;
    gsize len;
    SearpcClient *client = NULL;
    int ret = 0;

    client = ccnet_create_pooled_rpc_client (seaf->client_pool,
                                             NULL,
                                             "ccnet-rpcserver");
    if (!client) {
        seaf_warning ("Failed to create rpc client.\n");
        send_handshake_response (server, STATUS_INTERNAL_SERVER_ERROR);
        ret = -1;
        goto out;
    }

    enc_key_b64 = g_base64_encode (enc_session_key, server->session_key_len);

    key_b64 = ccnet_privkey_decrypt (client, enc_key_b64);
    if (!key_b64) {
        seaf_warning ("Failed to decrypt session key.\n");
        send_handshake_response (server, STATUS_INTERNAL_SERVER_ERROR);
        ret = -1;
        goto out;
    }

    session_key = g_base64_decode (key_b64, &len);

    if (server->version == 1)
        blocktx_generate_encrypt_key (session_key, len, server->key, server->iv);
    else if (server->version == 2)
        blocktx_generate_encrypt_key (session_key, len, server->key_v2, server->iv_v2);

    init_frame_parser (server);

out:
    g_free (enc_key_b64);
    g_free (key_b64);
    g_free (session_key);
    ccnet_rpc_client_free (client);

    return ret;
}
Example #6
0
static gint64
repo_share_usage (const char *user, const char *repo_id)
{
    GHashTable *user_hash;
    int dummy;
    GList *personal = NULL, *groups = NULL, *members = NULL, *p;
    SearpcClient *client = NULL;
    gint64 usage = -1;

    /* seaf_debug ("Computing share usage for repo %s.\n", repo_id); */

    /* If a repo is shared to both a user and a group, and that user is also
     * a member of the group, we don't want to count that user twice.
     * This also applies to two groups with overlapped members.
     * So we have to use a hash table to filter out duplicated users.
     */
    user_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);

    /* First count personal share */
    personal = seaf_share_manager_list_shared_to (seaf->share_mgr, user, repo_id);
    for (p = personal; p; p = p->next) {
        char *email = p->data;
        g_hash_table_insert (user_hash, g_strdup(email), &dummy);
        /* seaf_debug ("Shared to %s.\n", email); */
    }

    /* Then groups... */
    client = ccnet_create_pooled_rpc_client (seaf->client_pool,
                                             NULL,
                                             "ccnet-threaded-rpcserver");
    if (!client) {
        seaf_warning ("Failed to alloc rpc client.\n");
        goto out;
    }

    groups = seaf_repo_manager_get_groups_by_repo (seaf->repo_mgr,
                                                   repo_id, NULL);
    for (p = groups; p; p = p->next) {
        members = ccnet_get_group_members (client, (int)p->data);
        if (!members) {
            seaf_warning ("Cannot get member list for groupd %d.\n", (int)p->data);
            goto out;
        }

        count_group_members (user_hash, members);
    }

    /* Remove myself if i'm in a group. */
    g_hash_table_remove (user_hash, user);

    guint n_shared_to = g_hash_table_size(user_hash);
    /* seaf_debug ("n_shared_to = %u.\n", n_shared_to); */
    if (n_shared_to == 0) {
        usage = 0;
        goto out;
    }

    gint64 size = seaf_repo_manager_get_repo_size (seaf->repo_mgr, repo_id);
    if (size < 0) {
        seaf_warning ("Cannot get size of repo %s.\n", repo_id);
        goto out;
    }

    /* share_usage = repo_size * n_shared_to / 2 */
    usage = size * n_shared_to / 2;

out:
    g_hash_table_destroy (user_hash);
    string_list_free (personal);
    g_list_free (groups);
    ccnet_rpc_client_free (client);
    return usage;
}
Example #7
0
/*
 * Permission priority: owner --> personal share --> group share --> public.
 * Permission with higher priority overwrites those with lower priority.
 */
static char *
check_repo_share_permission (SeafRepoManager *mgr,
                             const char *repo_id,
                             const char *user_name)
{
    SearpcClient *rpc_client;
    GList *groups, *p1;
    GList *group_perms, *p2;
    CcnetGroup *group;
    GroupPerm *perm;
    int group_id;
    char *permission;

    permission = seaf_share_manager_check_permission (seaf->share_mgr,
                 repo_id,
                 user_name);
    if (permission != NULL)
        return permission;
    g_free (permission);

    rpc_client = ccnet_create_pooled_rpc_client (seaf->client_pool,
                 NULL,
                 "ccnet-threaded-rpcserver");
    if (!rpc_client)
        return NULL;

    /* Get the groups this user belongs to. */
    groups = ccnet_get_groups_by_user (rpc_client, user_name);

    ccnet_rpc_client_free (rpc_client);

    /* Get the groups this repo shared to. */
    group_perms = seaf_repo_manager_get_group_perm_by_repo (mgr, repo_id, NULL);

    permission = NULL;
    /* Check if any one group overlaps. */
    for (p1 = groups; p1 != NULL; p1 = p1->next) {
        group = p1->data;
        g_object_get (group, "id", &group_id, NULL);

        for (p2 = group_perms; p2 != NULL; p2 = p2->next) {
            perm = p2->data;
            if (group_id == perm->group_id) {
                /* If the repo is shared to more than 1 groups,
                 * and user is in more than 1 of these groups,
                 * "rw" permission will overwrite "ro" permission.
                 */
                if (g_strcmp0(perm->permission, "rw") == 0) {
                    permission = perm->permission;
                    goto group_out;
                } else if (g_strcmp0(perm->permission, "r") == 0 &&
                           !permission) {
                    permission = perm->permission;
                }
            }
        }
    }

group_out:
    if (permission != NULL)
        permission = g_strdup(permission);

    for (p1 = groups; p1 != NULL; p1 = p1->next)
        g_object_unref ((GObject *)p1->data);
    g_list_free (groups);
    for (p2 = group_perms; p2 != NULL; p2 = p2->next)
        g_free (p2->data);
    g_list_free (group_perms);

    if (permission != NULL)
        return permission;

    if (!mgr->seaf->cloud_mode)
        return seaf_repo_manager_get_inner_pub_repo_perm (mgr, repo_id);

    return NULL;
}
Example #8
0
static evhtp_res
upload_headers_cb (evhtp_request_t *req, evhtp_headers_t *hdr, void *arg)
{
    SearpcClient *rpc_client = NULL;
    char *token, *repo_id = NULL, *user = NULL;
    char *boundary = NULL;
    gint64 content_len;
    char *progress_id = NULL;
    char *err_msg = NULL;
    RecvFSM *fsm = NULL;
    Progress *progress = NULL;

    /* URL format: http://host:port/[upload|update]/<token>?X-Progress-ID=<uuid> */
    token = req->uri->path->file;
    if (!token) {
        seaf_warning ("[upload] No token in url.\n");
        err_msg = "Invalid URL";
        goto err;
    }

    rpc_client = ccnet_create_pooled_rpc_client (seaf->client_pool,
                                                 NULL,
                                                 "seafserv-rpcserver");

    if (check_access_token (rpc_client, token, &repo_id, &user) < 0) {
        seaf_warning ("[upload] Invalid token.\n");
        err_msg = "Access denied";
        goto err;
    }

    boundary = get_boundary (hdr);
    if (!boundary) {
        goto err;
    }

    if (get_progress_info (req, hdr, &content_len, &progress_id) < 0)
        goto err;

    progress = g_new0 (Progress, 1);
    progress->size = content_len;

    fsm = g_new0 (RecvFSM, 1);
    fsm->boundary = boundary;
    fsm->repo_id = repo_id;
    fsm->user = user;
    fsm->line = evbuffer_new ();
    fsm->form_kvs = g_hash_table_new_full (g_str_hash, g_str_equal,
                                           g_free, g_free);
    fsm->progress_id = progress_id;
    fsm->progress = progress;

    pthread_mutex_lock (&pg_lock);
    g_hash_table_insert (upload_progress, g_strdup(progress_id), progress);
    pthread_mutex_unlock (&pg_lock);

    /* Set up per-request hooks, so that we can read file data piece by piece. */
    evhtp_set_hook (&req->hooks, evhtp_hook_on_read, upload_read_cb, fsm);
    evhtp_set_hook (&req->hooks, evhtp_hook_on_request_fini, upload_finish_cb, fsm);
    /* Set arg for upload_cb or update_cb. */
    req->cbarg = fsm;

    ccnet_rpc_client_free (rpc_client);

    return EVHTP_RES_OK;

err:
    /* Don't receive any data before the connection is closed. */
    evhtp_request_pause (req);

    /* Set keepalive to 0. This will cause evhtp to close the
     * connection after sending the reply.
     */
    req->keepalive = 0;
    if (err_msg)
        evbuffer_add_printf (req->buffer_out, "%s\n", err_msg);
    evhtp_send_reply (req, EVHTP_RES_BADREQ);

    if (rpc_client)
        ccnet_rpc_client_free (rpc_client);

    g_free (repo_id);
    g_free (user);
    g_free (boundary);
    return EVHTP_RES_OK;
}
Example #9
0
static void
update_cb(evhtp_request_t *req, void *arg)
{
    RecvFSM *fsm = arg;
    SearpcClient *rpc_client = NULL;
    char *target_file, *parent_dir = NULL, *filename = NULL;
    const char *head_id = NULL;
    GError *error = NULL;
    int error_code = ERROR_INTERNAL;

    if (!fsm || fsm->state == RECV_ERROR)
        return;

    if (!fsm->tmp_files) {
        seaf_warning ("[update] No file uploaded.\n");
        evhtp_send_reply (req, EVHTP_RES_BADREQ);
        return;
    }

    target_file = g_hash_table_lookup (fsm->form_kvs, "target_file");
    if (!target_file) {
        seaf_warning ("[Update] No target file given.\n");
        evbuffer_add_printf(req->buffer_out, "Invalid URL.\n");
        evhtp_send_reply (req, EVHTP_RES_BADREQ);
        return;
    }

    parent_dir = g_path_get_dirname (target_file);
    filename = g_path_get_basename (target_file);

    if (!check_tmp_file_list (fsm->tmp_files, &error_code))
        goto error;

    head_id = evhtp_kv_find (req->uri->query, "head");

    rpc_client = ccnet_create_pooled_rpc_client (seaf->client_pool,
                                                 NULL,
                                                 "seafserv-threaded-rpcserver");

    if (seafile_check_quota (rpc_client, fsm->repo_id, NULL) < 0) {
        seaf_warning ("[update] Out of quota.\n");
        error_code = ERROR_QUOTA;
        goto error;
    }

    seafile_put_file (rpc_client,
                      fsm->repo_id,
                      (char *)(fsm->tmp_files->data),
                      parent_dir,
                      filename,
                      fsm->user,
                      head_id,
                      &error);
    if (error) {
        if (g_strcmp0 (error->message, "file does not exist") == 0) {
            error_code = ERROR_NOT_EXIST;
        }
        if (error->message)
            printf ("%s\n", error->message);
        g_clear_error (&error);
        goto error;
    }

    ccnet_rpc_client_free (rpc_client);

    /* Redirect to repo dir page after upload finishes. */
    redirect_to_success_page (req, fsm->repo_id, parent_dir);
    g_free (parent_dir);
    g_free (filename);
    return;

error:
    if (rpc_client)
        ccnet_rpc_client_free (rpc_client);

    redirect_to_update_error (req, fsm->repo_id, target_file, error_code);
    g_free (parent_dir);
    g_free (filename);
}
Example #10
0
static void
upload_cb(evhtp_request_t *req, void *arg)
{
    RecvFSM *fsm = arg;
    SearpcClient *rpc_client = NULL;
    char *parent_dir;
    GError *error = NULL;
    int error_code = ERROR_INTERNAL;
    char *err_file = NULL;
    char *filenames_json, *tmp_files_json;

    /* After upload_headers_cb() returns an error, libevhtp may still
     * receive data from the web browser and call into this cb.
     * In this case fsm will be NULL.
     */
    if (!fsm || fsm->state == RECV_ERROR)
        return;

    if (!fsm->tmp_files) {
        seaf_warning ("[upload] No file uploaded.\n");
        evhtp_send_reply (req, EVHTP_RES_BADREQ);
        return;
    }

    parent_dir = g_hash_table_lookup (fsm->form_kvs, "parent_dir");
    if (!parent_dir) {
        seaf_warning ("[upload] No parent dir given.\n");
        evbuffer_add_printf(req->buffer_out, "Invalid URL.\n");
        evhtp_send_reply (req, EVHTP_RES_BADREQ);
        return;
    }

    if (!check_tmp_file_list (fsm->tmp_files, &error_code))
        goto error;

    rpc_client = ccnet_create_pooled_rpc_client (seaf->client_pool,
                                                 NULL,
                                                 "seafserv-threaded-rpcserver");

    if (seafile_check_quota (rpc_client, fsm->repo_id, NULL) < 0) {
        seaf_warning ("[upload] Out of quota.\n");
        error_code = ERROR_QUOTA;
        goto error;
    }

    filenames_json = file_list_to_json (fsm->uploaded_files);
    tmp_files_json = file_list_to_json (fsm->tmp_files);

    seafile_post_multi_files (rpc_client,
                              fsm->repo_id,
                              parent_dir,
                              filenames_json,
                              tmp_files_json,
                              fsm->user,
                              &error);
    g_free (filenames_json);
    g_free (tmp_files_json);
    if (error) {
        if (error->code == POST_FILE_ERR_FILENAME) {
            error_code = ERROR_FILENAME;
            err_file = g_strdup(error->message);
        }
        g_clear_error (&error);
        goto error;
    }

    ccnet_rpc_client_free (rpc_client);

    /* Redirect to repo dir page after upload finishes. */
    redirect_to_success_page (req, fsm->repo_id, parent_dir);
    return;

error:
    if (rpc_client)
        ccnet_rpc_client_free (rpc_client);

    redirect_to_upload_error (req, fsm->repo_id, parent_dir,
                              err_file, error_code);
    g_free (err_file);
}
Example #11
0
static void
update_api_cb(evhtp_request_t *req, void *arg)
{
    RecvFSM *fsm = arg;
    SearpcClient *rpc_client = NULL;
    char *target_file, *parent_dir = NULL, *filename = NULL;
    const char *head_id = NULL;
    GError *error = NULL;
    int error_code = ERROR_INTERNAL;
    char *new_file_id = NULL;

    if (!fsm || fsm->state == RECV_ERROR)
        return;

    if (!fsm->files) {
        seaf_warning ("[update] No file uploaded.\n");
        set_content_length_header (req);
        evhtp_send_reply (req, EVHTP_RES_BADREQ);
        return;
    }

    target_file = g_hash_table_lookup (fsm->form_kvs, "target_file");
    if (!target_file) {
        seaf_warning ("[Update] No target file given.\n");
        evbuffer_add_printf(req->buffer_out, "Invalid URL.\n");
        set_content_length_header (req);
        evhtp_send_reply (req, EVHTP_RES_BADREQ);
        return;
    }

    parent_dir = g_path_get_dirname (target_file);
    filename = g_path_get_basename (target_file);

    if (!check_tmp_file_list (fsm->files, &error_code))
        goto error;

    head_id = evhtp_kv_find (req->uri->query, "head");

    rpc_client = ccnet_create_pooled_rpc_client (seaf->client_pool,
                                                 NULL,
                                                 "seafserv-threaded-rpcserver");

    if (seafile_check_quota (rpc_client, fsm->repo_id, NULL) < 0) {
        seaf_warning ("[update] Out of quota.\n");
        error_code = ERROR_QUOTA;
        goto error;
    }

    new_file_id = seafile_put_file (rpc_client,
                                    fsm->repo_id,
                                    (char *)(fsm->files->data),
                                    parent_dir,
                                    filename,
                                    fsm->user,
                                    head_id,
                                    &error);
    g_free (parent_dir);
    g_free (filename);
    
    if (error) {
        if (g_strcmp0 (error->message, "file does not exist") == 0) {
            error_code = ERROR_NOT_EXIST;
        }
        if (error->message)
            seaf_warning ("%s\n", error->message);
        g_clear_error (&error);
        goto error;
    }

    ccnet_rpc_client_free (rpc_client);
    /* Send back the new file id, so that the mobile client can update local cache */
    evbuffer_add(req->buffer_out, new_file_id, strlen(new_file_id));
    set_content_length_header (req);
    evhtp_send_reply (req, EVHTP_RES_OK);

    g_free (new_file_id);
    return;

error:
    if (rpc_client)
        ccnet_rpc_client_free (rpc_client);

    switch (error_code) {
    case ERROR_FILENAME:
        evbuffer_add_printf(req->buffer_out, "Invalid filename.\n");
        set_content_length_header (req);
        evhtp_send_reply (req, SEAF_HTTP_RES_BADFILENAME);
        break;
    case ERROR_EXISTS:
        evbuffer_add_printf(req->buffer_out, "File already exists.\n");
        set_content_length_header (req);
        evhtp_send_reply (req, SEAF_HTTP_RES_EXISTS);
        break;
    case ERROR_SIZE:
        evbuffer_add_printf(req->buffer_out, "File size is too large.\n");
        set_content_length_header (req);
        evhtp_send_reply (req, SEAF_HTTP_RES_TOOLARGE);
        break;
    case ERROR_QUOTA:
        evbuffer_add_printf(req->buffer_out, "Out of quota.\n");
        set_content_length_header (req);
        evhtp_send_reply (req, SEAF_HTTP_RES_NOQUOTA);
        break;
    case ERROR_NOT_EXIST:
        evbuffer_add_printf(req->buffer_out, "File does not exist.\n");
        set_content_length_header (req);
        evhtp_send_reply (req, SEAF_HTTP_RES_NOT_EXISTS);
        break;
    case ERROR_RECV:
    case ERROR_INTERNAL:
    default:
        set_content_length_header (req);
        evhtp_send_reply (req, EVHTP_RES_SERVERR);
        break;
    }
}
Example #12
0
/*
  Handle AJAX file upload.
  @return an array of json data, e.g. [{"name": "foo.txt"}]
 */
static void
upload_ajax_cb(evhtp_request_t *req, void *arg)
{
    RecvFSM *fsm = arg;
    SearpcClient *rpc_client = NULL;
    char *parent_dir;
    GError *error = NULL;
    int error_code = ERROR_INTERNAL;
    char *filenames_json, *tmp_files_json;

    evhtp_headers_add_header (req->headers_out,
                              evhtp_header_new("Access-Control-Allow-Headers",
                                               "x-requested-with, content-type, accept, origin, authorization", 1, 1));
    evhtp_headers_add_header (req->headers_out,
                              evhtp_header_new("Access-Control-Allow-Methods",
                                               "GET, POST, PUT, PATCH, DELETE, OPTIONS", 1, 1));
    evhtp_headers_add_header (req->headers_out,
                              evhtp_header_new("Access-Control-Allow-Origin",
                                               "*", 1, 1));
    evhtp_headers_add_header (req->headers_out,
                              evhtp_header_new("Access-Control-Max-Age",
                                               "86400", 1, 1));

    if (evhtp_request_get_method(req) == htp_method_OPTIONS) {
        /* If CORS preflight header, then create an empty body response (200 OK)
         * and return it.
         */
         evhtp_headers_add_header (req->headers_out,
                                   evhtp_header_new("Content-Type",
                                                    "text/html; charset=utf-8", 1, 1));         
         
         set_content_length_header (req);
         evhtp_send_reply (req, EVHTP_RES_OK);
         return;
    }

    /* After upload_headers_cb() returns an error, libevhtp may still
     * receive data from the web browser and call into this cb.
     * In this case fsm will be NULL.
     */
    if (!fsm || fsm->state == RECV_ERROR)
        return;

    if (!fsm->files) {
        seaf_warning ("[upload] No file uploaded.\n");
        set_content_length_header (req);
        evhtp_send_reply (req, EVHTP_RES_BADREQ);
        return;
    }

    parent_dir = g_hash_table_lookup (fsm->form_kvs, "parent_dir");
    if (!parent_dir) {
        seaf_warning ("[upload] No parent dir given.\n");
        evbuffer_add_printf(req->buffer_out, "Invalid URL.\n");
        set_content_length_header (req);
        evhtp_send_reply (req, EVHTP_RES_BADREQ);
        return;
    }

    if (!check_tmp_file_list (fsm->files, &error_code))
        goto error;

    rpc_client = ccnet_create_pooled_rpc_client (seaf->client_pool,
                                                 NULL,
                                                 "seafserv-threaded-rpcserver");

    if (seafile_check_quota (rpc_client, fsm->repo_id, NULL) < 0) {
        seaf_warning ("[upload] Out of quota.\n");
        error_code = ERROR_QUOTA;
        goto error;
    }

    filenames_json = file_list_to_json (fsm->filenames);
    tmp_files_json = file_list_to_json (fsm->files);

    seafile_post_multi_files (rpc_client,
                              fsm->repo_id,
                              parent_dir,
                              filenames_json,
                              tmp_files_json,
                              fsm->user,
                              &error);
    g_free (filenames_json);
    g_free (tmp_files_json);
    if (error) {
        if (error->code == POST_FILE_ERR_FILENAME) {
            error_code = ERROR_FILENAME;
            seaf_warning ("[upload] Bad filename.\n");
        }
        g_clear_error (&error);
        goto error;
    }

    ccnet_rpc_client_free (rpc_client);

    GString *res_buf = g_string_new (NULL);
    GList *ptr;

    g_string_append (res_buf, "[");
    for (ptr = fsm->filenames; ptr; ptr = ptr->next) {
        char *filename = ptr->data;
        if (ptr->next)
            g_string_append_printf (res_buf, "{\"name\": \"%s\"}, ", filename);
        else
            g_string_append_printf (res_buf, "{\"name\": \"%s\"}", filename);
    }
    g_string_append (res_buf, "]");

    evbuffer_add (req->buffer_out, res_buf->str, res_buf->len);
    g_string_free (res_buf, TRUE);

    set_content_length_header (req);
    evhtp_send_reply (req, EVHTP_RES_OK);
    return;

error:
    if (rpc_client)
        ccnet_rpc_client_free (rpc_client);

    switch (error_code) {
    case ERROR_FILENAME:
        evbuffer_add_printf(req->buffer_out, "Invalid filename.\n");
        set_content_length_header (req);
        evhtp_send_reply (req, SEAF_HTTP_RES_BADFILENAME);
        break;
    case ERROR_EXISTS:
        evbuffer_add_printf(req->buffer_out, "File already exists.\n");
        set_content_length_header (req);
        evhtp_send_reply (req, SEAF_HTTP_RES_EXISTS);
        break;
    case ERROR_SIZE:
        evbuffer_add_printf(req->buffer_out, "File size is too large.\n");
        set_content_length_header (req);
        evhtp_send_reply (req, SEAF_HTTP_RES_TOOLARGE);
        break;
    case ERROR_QUOTA:
        evbuffer_add_printf(req->buffer_out, "Out of quota.\n");
        set_content_length_header (req);
        evhtp_send_reply (req, SEAF_HTTP_RES_NOQUOTA);
        break;
    case ERROR_RECV:
    case ERROR_INTERNAL:
        set_content_length_header (req);
        evhtp_send_reply (req, EVHTP_RES_SERVERR);
        break;
    }
}
Example #13
0
static void
upload_api_cb(evhtp_request_t *req, void *arg)
{
    RecvFSM *fsm = arg;
    SearpcClient *rpc_client = NULL;
    char *parent_dir;
    GError *error = NULL;
    int error_code = ERROR_INTERNAL;
    char *filenames_json, *tmp_files_json;

    /* After upload_headers_cb() returns an error, libevhtp may still
     * receive data from the web browser and call into this cb.
     * In this case fsm will be NULL.
     */
    if (!fsm || fsm->state == RECV_ERROR)
        return;

    if (!fsm->files) {
        seaf_warning ("[upload] No file uploaded.\n");
        set_content_length_header (req);
        evhtp_send_reply (req, EVHTP_RES_BADREQ);
        return;
    }

    parent_dir = g_hash_table_lookup (fsm->form_kvs, "parent_dir");
    if (!parent_dir) {
        seaf_warning ("[upload] No parent dir given.\n");
        evbuffer_add_printf(req->buffer_out, "Invalid URL.\n");
        set_content_length_header (req);
        evhtp_send_reply (req, EVHTP_RES_BADREQ);
        return;
    }

    if (!check_tmp_file_list (fsm->files, &error_code))
        goto error;

    rpc_client = ccnet_create_pooled_rpc_client (seaf->client_pool,
                                                 NULL,
                                                 "seafserv-threaded-rpcserver");

    if (seafile_check_quota (rpc_client, fsm->repo_id, NULL) < 0) {
        seaf_warning ("[upload] Out of quota.\n");
        error_code = ERROR_QUOTA;
        goto error;
    }

    filenames_json = file_list_to_json (fsm->filenames);
    tmp_files_json = file_list_to_json (fsm->files);

    char *new_file_ids = seafile_post_multi_files (rpc_client,
                                              fsm->repo_id,
                                              parent_dir,
                                              filenames_json,
                                              tmp_files_json,
                                              fsm->user,
                                              &error);
    g_free (filenames_json);
    g_free (tmp_files_json);
    if (error) {
        if (error->code == POST_FILE_ERR_FILENAME) {
            error_code = ERROR_FILENAME;
            seaf_warning ("[upload] Bad filename.\n");
        }
        g_clear_error (&error);
        goto error;
    }

    ccnet_rpc_client_free (rpc_client);

    evbuffer_add (req->buffer_out, new_file_ids, strlen(new_file_ids));
    g_free (new_file_ids);
    set_content_length_header (req);
    evhtp_send_reply (req, EVHTP_RES_OK);
    return;

error:
    if (rpc_client)
        ccnet_rpc_client_free (rpc_client);

    switch (error_code) {
    case ERROR_FILENAME:
        evbuffer_add_printf(req->buffer_out, "Invalid filename.\n");
        set_content_length_header (req);
        evhtp_send_reply (req, SEAF_HTTP_RES_BADFILENAME);
        break;
    case ERROR_EXISTS:
        evbuffer_add_printf(req->buffer_out, "File already exists.\n");
        set_content_length_header (req);
        evhtp_send_reply (req, SEAF_HTTP_RES_EXISTS);
        break;
    case ERROR_SIZE:
        evbuffer_add_printf(req->buffer_out, "File size is too large.\n");
        set_content_length_header (req);
        evhtp_send_reply (req, SEAF_HTTP_RES_TOOLARGE);
        break;
    case ERROR_QUOTA:
        evbuffer_add_printf(req->buffer_out, "Out of quota.\n");
        set_content_length_header (req);
        evhtp_send_reply (req, SEAF_HTTP_RES_NOQUOTA);
        break;
    case ERROR_RECV:
    case ERROR_INTERNAL:
        set_content_length_header (req);
        evhtp_send_reply (req, EVHTP_RES_SERVERR);
        break;
    }
}