summaryrefslogblamecommitdiffstats
path: root/src/nxt_unit_app_test.c
blob: 92335137f0135d9b1eb0220cea9d97ea4e26a37a (plain) (tree)
1
2
3
4
5
6
7
8






                             
                        




                    
                                                           

                                          

 

                                    



















                                                                       















































































































                                                                           
                                    



                                                            
                                                                    

                                                    

                                                          
                                                            




                                           

                                                                        



                                           






                                                                                
                                                                      


                                           
                                                                              












                                                                      



















                                                                   







                                     
                                                       
 
                                           
                                                                    

                
                                               
                                                                      

                
                                                     
                                                                    

                
                                                   
                                                                            

                
                                           
                                                                    

                
                                       
                                                                


                          
                                             
                                                                      


                    
                                           



                                           
                                                     
                                                                    
                                                     
                                                                      



                                
                                           








                                                                          



                                           
                                                                             




                                     
                                                                              




                                      



                                                                       









                                           
 






                                                                 



                                   

/*
 * Copyright (C) NGINX, Inc.
 */

#include <nxt_unit.h>
#include <nxt_unit_request.h>
//#include <nxt_clang.h>
#include <pthread.h>
#include <string.h>
#include <stdlib.h>


#define nxt_expect(c, x)  __builtin_expect((long) (x), (c))
#define nxt_fast_path(x)  nxt_expect(1, x)
#define nxt_slow_path(x)  nxt_expect(0, x)


#define CONTENT_TYPE  "Content-Type"
#define TEXT_PLAIN    "text/plain"

#define NEW_LINE      "\n"

#define REQUEST_DATA  "Request data:\n"
#define METHOD        "  Method: "
#define PROTOCOL      "  Protocol: "
#define REMOTE_ADDR   "  Remote addr: "
#define LOCAL_ADDR    "  Local addr: "
#define TARGET        "  Target: "
#define PATH          "  Path: "
#define QUERY         "  Query: "
#define FIELDS        "  Fields:\n"
#define FIELD_PAD     "    "
#define FIELD_SEP     ": "
#define BODY          "  Body:\n"


static int ready_handler(nxt_unit_ctx_t *ctx);
static void *worker(void *main_ctx);
static void greeting_app_request_handler(nxt_unit_request_info_t *req);


static int        thread_count;
static pthread_t  *threads;


int
main(int argc, char **argv)
{
    int              i, err;
    nxt_unit_ctx_t   *ctx;
    nxt_unit_init_t  init;

    if (argc == 3 && strcmp(argv[1], "-t") == 0) {
        thread_count = atoi(argv[2]);
    }

    memset(&init, 0, sizeof(nxt_unit_init_t));

    init.callbacks.request_handler = greeting_app_request_handler;
    init.callbacks.ready_handler = ready_handler;

    ctx = nxt_unit_init(&init);
    if (ctx == NULL) {
        return 1;
    }

    err = nxt_unit_run(ctx);

    nxt_unit_debug(ctx, "main worker finished with %d code", err);

    if (thread_count > 1) {
        for (i = 0; i < thread_count - 1; i++) {
            err = pthread_join(threads[i], NULL);

            if (nxt_fast_path(err == 0)) {
                nxt_unit_debug(ctx, "join thread #%d", i);

            } else {
                nxt_unit_alert(ctx, "pthread_join(#%d) failed: %s (%d)",
                                    i, strerror(err), err);
            }
        }

        nxt_unit_free(ctx, threads);
    }

    nxt_unit_done(ctx);

    nxt_unit_debug(NULL, "main worker done");

    return 0;
}


static int
ready_handler(nxt_unit_ctx_t *ctx)
{
    int  i, err;

    nxt_unit_debug(ctx, "ready");

    if (thread_count <= 1) {
        return NXT_UNIT_OK;
    }

    threads = nxt_unit_malloc(ctx, sizeof(pthread_t) * (thread_count - 1));
    if (threads == NULL) {
        return NXT_UNIT_ERROR;
    }

    for (i = 0; i < thread_count - 1; i++) {
        err = pthread_create(&threads[i], NULL, worker, ctx);
        if (err != 0) {
            return NXT_UNIT_ERROR;
        }
    }

    return NXT_UNIT_OK;
}


static void *
worker(void *main_ctx)
{
    int             rc;
    nxt_unit_ctx_t  *ctx;

    ctx = nxt_unit_ctx_alloc(main_ctx, NULL);
    if (ctx == NULL) {
        return NULL;
    }

    nxt_unit_debug(ctx, "start worker");

    rc = nxt_unit_run(ctx);

    nxt_unit_debug(ctx, "worker finished with %d code", rc);

    nxt_unit_done(ctx);

    return (void *) (intptr_t) rc;
}


static void
greeting_app_request_handler(nxt_unit_request_info_t *req)
{
    int                 rc;
    char                *p;
    ssize_t             res;
    uint32_t            i;
    nxt_unit_buf_t      *buf, *buf2;
    nxt_unit_field_t    *f;
    nxt_unit_request_t  *r;

    rc = nxt_unit_response_init(req, 200 /* Status code. */,
                                2 /* Number of response headers. */,
                                strlen(CONTENT_TYPE)
                                + strlen(TEXT_PLAIN)
                                + strlen("Content-Length")
                                + strlen("42")
                                + strlen("Hello world\n!"));
    if (nxt_slow_path(rc != NXT_UNIT_OK)) {
        goto fail;
    }

    rc = nxt_unit_response_add_field(req,
                                     CONTENT_TYPE, strlen(CONTENT_TYPE),
                                     TEXT_PLAIN, strlen(TEXT_PLAIN));
    if (nxt_slow_path(rc != NXT_UNIT_OK)) {
        goto fail;
    }

    rc = nxt_unit_response_add_field(req,
                                     "Content-Length", strlen("Content-Length"),
                                     "42", strlen("42"));
    if (nxt_slow_path(rc != NXT_UNIT_OK)) {
        goto fail;
    }

    rc = nxt_unit_response_add_content(req, "Hello", strlen("Hello"));
    if (nxt_slow_path(rc != NXT_UNIT_OK)) {
        goto fail;
    }
    rc = nxt_unit_response_add_content(req, " world!\n", strlen(" world!\n"));
    if (nxt_slow_path(rc != NXT_UNIT_OK)) {
        goto fail;
    }

    rc = nxt_unit_response_send(req);
    if (nxt_slow_path(rc != NXT_UNIT_OK)) {
        goto fail;
    }

    r = req->request;

    buf = nxt_unit_response_buf_alloc(req, (req->request_buf->end
                                            - req->request_buf->start)
                                           + strlen(REQUEST_DATA)
                                           + strlen(METHOD)
                                           + strlen(NEW_LINE)
                                           + strlen(PROTOCOL)
                                           + strlen(NEW_LINE)
                                           + strlen(REMOTE_ADDR)
                                           + strlen(NEW_LINE)
                                           + strlen(LOCAL_ADDR)
                                           + strlen(NEW_LINE)
                                           + strlen(TARGET)
                                           + strlen(NEW_LINE)
                                           + strlen(PATH)
                                           + strlen(NEW_LINE)
                                           + strlen(QUERY)
                                           + strlen(NEW_LINE)
                                           + strlen(FIELDS)
                                           + r->fields_count * (
                                               strlen(FIELD_PAD)
                                               + strlen(FIELD_SEP))
                                           + strlen(BODY));
    if (nxt_slow_path(buf == NULL)) {
        rc = NXT_UNIT_ERROR;

        goto fail;
    }

    p = buf->free;

    p = mempcpy(p, REQUEST_DATA, strlen(REQUEST_DATA));

    p = mempcpy(p, METHOD, strlen(METHOD));
    p = mempcpy(p, nxt_unit_sptr_get(&r->method), r->method_length);
    *p++ = '\n';

    p = mempcpy(p, PROTOCOL, strlen(PROTOCOL));
    p = mempcpy(p, nxt_unit_sptr_get(&r->version), r->version_length);
    *p++ = '\n';

    p = mempcpy(p, REMOTE_ADDR, strlen(REMOTE_ADDR));
    p = mempcpy(p, nxt_unit_sptr_get(&r->remote), r->remote_length);
    *p++ = '\n';

    p = mempcpy(p, LOCAL_ADDR, strlen(LOCAL_ADDR));
    p = mempcpy(p, nxt_unit_sptr_get(&r->local_addr), r->local_addr_length);
    *p++ = '\n';

    p = mempcpy(p, TARGET, strlen(TARGET));
    p = mempcpy(p, nxt_unit_sptr_get(&r->target), r->target_length);
    *p++ = '\n';

    p = mempcpy(p, PATH, strlen(PATH));
    p = mempcpy(p, nxt_unit_sptr_get(&r->path), r->path_length);
    *p++ = '\n';

    if (r->query.offset) {
        p = mempcpy(p, QUERY, strlen(QUERY));
        p = mempcpy(p, nxt_unit_sptr_get(&r->query), r->query_length);
        *p++ = '\n';
    }

    p = mempcpy(p, FIELDS, strlen(FIELDS));

    for (i = 0; i < r->fields_count; i++) {
        f = r->fields + i;

        p = mempcpy(p, FIELD_PAD, strlen(FIELD_PAD));
        p = mempcpy(p, nxt_unit_sptr_get(&f->name), f->name_length);
        p = mempcpy(p, FIELD_SEP, strlen(FIELD_SEP));
        p = mempcpy(p, nxt_unit_sptr_get(&f->value), f->value_length);
        *p++ = '\n';
    }

    if (r->content_length > 0) {
        p = mempcpy(p, BODY, strlen(BODY));

        res = nxt_unit_request_read(req, buf->free, buf->end - buf->free);
        buf->free += res;

    }

    buf->free = p;

    rc = nxt_unit_buf_send(buf);
    if (nxt_slow_path(rc != NXT_UNIT_OK)) {
        goto fail;
    }

    buf = nxt_unit_response_buf_alloc(req, strlen("Some extra contents.\n"));
    if (nxt_slow_path(buf == NULL)) {
        rc = NXT_UNIT_ERROR;
        goto fail;
    }

    buf2 = nxt_unit_response_buf_alloc(req, strlen("But send this first.\n"));
    if (nxt_slow_path(buf2 == NULL)) {
        rc = NXT_UNIT_ERROR;
        goto fail;
    }

    buf2->free = mempcpy(buf2->free, "But send this first.\n",
                                     strlen("But send this first.\n"));
    buf->free  = mempcpy(buf->free, "Some extra contents.\n",
                                    strlen("Some extra contents.\n"));

    rc = nxt_unit_buf_send(buf2);
    if (nxt_slow_path(rc != NXT_UNIT_OK)) {
        goto fail;
    }

    rc = nxt_unit_buf_send(buf);
    if (nxt_slow_path(rc != NXT_UNIT_OK)) {
        goto fail;
    }

    rc = nxt_unit_response_write(req, "And some more\n",
                                      strlen("And some more\n"));
    if (nxt_slow_path(rc != 0)) {
        goto fail;
    }


fail:

    nxt_unit_request_done(req, rc);
}