void HttpStack::handler_callback(evhtp_request_t* req,
                                 HttpStack::ControllerInterface* controller)
{
  Request request(this, req);

  // Call into the controller to request a SAS logger that can be used to log
  // this request.  Then actually log the request.
  request.set_sas_logger(controller->sas_logger(request));

  SAS::TrailId trail = SAS::new_trail(0);
  request.sas_log_rx_http_req(trail, 0);

  if (_stats != NULL)
  {
    _stats->incr_http_incoming_requests();
  }

  if ((_load_monitor == NULL) || _load_monitor->admit_request())
  {
    // Pause the request processing (which stops it from being cancelled), as we
    // may process this request asynchronously.  The
    // HttpStack::Request::send_reply method resumes.
    evhtp_request_pause(req);

    // Pass the request to the controller.
    LOG_VERBOSE("Process request for URL %s, args %s",
                req->uri->path->full,
                req->uri->query_raw);
    controller->process_request(request, trail);
  }
  else
  {
    request.sas_log_overload(trail, 503, 0);
    send_reply_internal(request, 503, trail);

    if (_stats != NULL)
    {
      _stats->incr_http_rejected_overload();
    }
  }
}
Exemple #2
0
static void
frontend_cb(evhtp_request_t * req, void * arg) {
    int * aux;
    int   thr;

    aux = (int *)evthr_get_aux(req->conn->thread);
    thr = *aux;

    printf("  Received frontend request on thread %d... ", thr);

    /* Pause the frontend request while we run the backend requests. */
    evhtp_request_pause(req);

    make_request(evthr_get_base(req->conn->thread),
                 req->conn->thread,
                 "127.0.0.1", 80,
                 req->uri->path->full,
                 req->headers_in, backend_cb, req);

    printf("Ok.\n");
}
Exemple #3
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;
}
Exemple #4
0
/*
   Example multipart form-data request content format:

   --AaB03x
   Content-Disposition: form-data; name="submit-name"

   Larry
   --AaB03x
   Content-Disposition: form-data; name="file"; filename="file1.txt"
   Content-Type: text/plain

   ... contents of file1.txt ...
   --AaB03x--
*/
static evhtp_res
upload_read_cb (evhtp_request_t *req, evbuf_t *buf, void *arg)
{
    RecvFSM *fsm = arg;
    char *line;
    size_t len;
    gboolean no_line = FALSE;
    int res = EVHTP_RES_OK;

    if (fsm->state == RECV_ERROR)
        return EVHTP_RES_OK;

    /* Update upload progress. */
    fsm->progress->uploaded += (gint64)evbuffer_get_length(buf);

    seaf_debug ("progress: %lld/%lld\n",
                fsm->progress->uploaded, fsm->progress->size);

    evbuffer_add_buffer (fsm->line, buf);
    /* Drain the buffer so that evhtp don't copy it to another buffer
     * after this callback returns. 
     */
    evbuffer_drain (buf, evbuffer_get_length (buf));

    while (!no_line) {
        switch (fsm->state) {
        case RECV_INIT:
            line = evbuffer_readln (fsm->line, &len, EVBUFFER_EOL_CRLF_STRICT);
            if (line != NULL) {
                seaf_debug ("[upload] boundary line: %s.\n", line);
                if (!strstr (line, fsm->boundary)) {
                    seaf_warning ("[upload] no boundary found in the first line.\n");
                    free (line);
                    res = EVHTP_RES_BADREQ;
                    goto out;
                } else {
                    fsm->state = RECV_HEADERS;
                    free (line);
                }
            } else {
                no_line = TRUE;
            }
            break;
        case RECV_HEADERS:
            line = evbuffer_readln (fsm->line, &len, EVBUFFER_EOL_CRLF_STRICT);
            if (line != NULL) {
                seaf_debug ("[upload] mime header line: %s.\n", line);
                if (len == 0) {
                    /* Read an blank line, headers end. */
                    free (line);
                    if (g_strcmp0 (fsm->input_name, "file") == 0) {
                        if (open_temp_file (fsm) < 0) {
                            seaf_warning ("[upload] Failed open temp file.\n");
                            res = EVHTP_RES_SERVERR;
                            goto out;
                        }
                    }
                    seaf_debug ("[upload] Start to recv %s.\n", fsm->input_name);
                    fsm->state = RECV_CONTENT;
                } else if (parse_mime_header (line, fsm) < 0) {
                    free (line);
                    res = EVHTP_RES_BADREQ;
                    goto out;
                } else {
                    free (line);
                }
            } else {
                no_line = TRUE;
            }
            break;
        case RECV_CONTENT:
            if (g_strcmp0 (fsm->input_name, "file") == 0)
                res = recv_file_data (fsm, &no_line);
            else
                res = recv_form_field (fsm, &no_line);

            if (res != EVHTP_RES_OK)
                goto out;

            break;
        }
    }

out:
    if (res != EVHTP_RES_OK) {
        /* 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;

        fsm->state = RECV_ERROR;
    }

    if (res == EVHTP_RES_BADREQ) {
        evhtp_send_reply (req, EVHTP_RES_BADREQ);
    } else if (res == EVHTP_RES_SERVERR) {
        evbuffer_add_printf (req->buffer_out, "Internal server error\n");
        evhtp_send_reply (req, EVHTP_RES_SERVERR);
    }
    return EVHTP_RES_OK;
}