Libevhtp: Difference between revisions

From 탱이의 잡동사니
Jump to navigation Jump to search
No edit summary
No edit summary
Line 258: Line 258:
  */
  */
int evhtp_unset_all_hooks(evhtp_hooks_t ** hooks);
int evhtp_unset_all_hooks(evhtp_hooks_t ** hooks);
/**
* @brief sets a callback which is called if no other callbacks are matched
*
* @param htp the initialized evhtp_t
* @param cb  the function to be executed
* @param arg user-defined argument passed to the callback
*/
void evhtp_set_gencb(evhtp_t * htp, evhtp_callback_cb cb, void * arg);
void evhtp_set_pre_accept_cb(evhtp_t * htp, evhtp_pre_accept_cb, void * arg);
void evhtp_set_post_accept_cb(evhtp_t * htp, evhtp_post_accept_cb, void * arg);


/**
/**
Line 279: Line 290:
};
};
</source>
</source>
각각의 HTTP 연결마다 호출되는 Hook 콜백 함수를 설정한다.
각각의 HTTP 연결마다 호출되는 Hook 콜백 함수를 설정한다. evhtp_set_gencb(), evhtp_set_pre_accept_cb(), evhtp_set_post_accept_cb() 함수들은 default callback 함수들을 지정한다.





Revision as of 14:06, 5 February 2015

Overview

libevhtp 는 libevent 를 이용한 HTTP API 라이브러리이다. libevhtp 를 사용하면 손쉽게 REST 인터페이스를 구현할 수 있다.

홈페이지: https://github.com/ellzey/libevhtp

Types

이벤트 베이스

<source lang=c> typedef struct evhtp_s evhtp_t;

/**

* @brief main structure containing all configuration information
*/

struct evhtp_s {

   evhtp_t  * parent;           /**< only when this is a vhost */
   evbase_t * evbase;           /**< the initialized event_base */
   evserv_t * server;           /**< the libevent listener struct */
   char     * server_name;      /**< the name included in Host: responses */
   void     * arg;              /**< user-defined evhtp_t specific arguments */
   int        bev_flags;        /**< bufferevent flags to use on bufferevent_*_socket_new() */
   uint64_t   max_body_size;
   uint64_t   max_keepalive_requests;
   int        disable_100_cont; /**< if set, evhtp will not respond to Expect: 100-continue */
  1. ifndef EVHTP_DISABLE_SSL
   evhtp_ssl_ctx_t * ssl_ctx;   /**< if ssl enabled, this is the servers CTX */
   evhtp_ssl_cfg_t * ssl_cfg;
  1. endif
  1. ifndef EVHTP_DISABLE_EVTHR
   evthr_pool_t * thr_pool;     /**< connection threadpool */
  1. endif
  1. ifndef EVHTP_DISABLE_EVTHR
   pthread_mutex_t    * lock;   /**< parent lock for add/del cbs in threads */
   evhtp_thread_init_cb thread_init_cb;
   void               * thread_init_cbarg;
  1. endif
   evhtp_callbacks_t * callbacks;
   evhtp_defaults_t    defaults;
   struct timeval recv_timeo;
   struct timeval send_timeo;
   TAILQ_HEAD(, evhtp_alias_s) aliases;
   TAILQ_HEAD(, evhtp_s) vhosts;
   TAILQ_ENTRY(evhtp_s) next_vhost;

}; </source>

이벤트 콜백

<source lang=c> typedef struct evhtp_callback_s evhtp_callback_t;

/**

* @brief structure containing a single callback and configuration
*
* The definition structure which is used within the evhtp_callbacks_t
* structure. This holds information about what should execute for either
* a single or regex path.
*
* For example, if you registered a callback to be executed on a request
* for "/herp/derp", your defined callback will be executed.
*
* Optionally you can set callback-specific hooks just like per-connection
* hooks using the same rules.
*
*/

struct evhtp_callback_s {

   evhtp_callback_type type;           /**< the type of callback (regex|path) */
   evhtp_callback_cb   cb;             /**< the actual callback function */
   unsigned int        hash;           /**< the full hash generated integer */
   void              * cbarg;          /**< user-defind arguments passed to the cb */
   evhtp_hooks_t     * hooks;          /**< per-callback hooks */
   union {
       char * path;
       char * glob;
  1. ifndef EVHTP_DISABLE_REGEX
       regex_t * regex;
  1. endif
   } val;
   TAILQ_ENTRY(evhtp_callback_s) next;

}; </source>

evhtp_request_t

HTTP request 요청시 모든 정보가 저장되는 구조체이다. <source lang=c> typedef struct evhtp_request_s evhtp_request_t;

/**

* @brief a structure containing all information for a http request.
*/

struct evhtp_request_s {

   evhtp_t            * htp;         /**< the parent evhtp_t structure */
   evhtp_connection_t * conn;        /**< the associated connection */
   evhtp_hooks_t      * hooks;       /**< request specific hooks */
   evhtp_uri_t        * uri;         /**< request URI information */
   evbuf_t            * buffer_in;   /**< buffer containing data from client */
   evbuf_t            * buffer_out;  /**< buffer containing data to client */
   evhtp_headers_t    * headers_in;  /**< headers from client */
   evhtp_headers_t    * headers_out; /**< headers to client */
   evhtp_proto          proto;       /**< HTTP protocol used */
   htp_method           method;      /**< HTTP method used */
   evhtp_res            status;      /**< The HTTP response code or other error conditions */
   int                  keepalive;   /**< set to 1 if the connection is keep-alive */
   int                  finished;    /**< set to 1 if the request is fully processed */
   int                  chunked;     /**< set to 1 if the request is chunked */
   evhtp_callback_cb cb;             /**< the function to call when fully processed */
   void            * cbarg;          /**< argument which is passed to the cb function */
   int               error;
   TAILQ_ENTRY(evhtp_request_s) next;

}; </source>

Functions

생성/삭제

<source lang=c> /**

* @brief creates a new evhtp_t instance
*
* @param evbase the initialized event base
* @param arg user-defined argument which is evhtp_t specific
*
* @return a new evhtp_t structure or NULL on error
*/

evhtp_t * evhtp_new(evbase_t * evbase, void * arg); void evhtp_free(evhtp_t * evhtp); </source> evhtp 인스턴스 생성/삭제 함수

콜백 관련

  • Interface

<source lang=c> /**

* @brief sets a callback to be executed on a specific path
*
* @param htp the initialized evhtp_t
* @param path the path to match
* @param cb the function to be executed
* @param arg user-defined argument passed to the callback
*
* @return evhtp_callback_t * on success, NULL on error.
*/

evhtp_callback_t * evhtp_set_cb(evhtp_t * htp, const char * path, evhtp_callback_cb cb, void * arg);

/**

* @brief sets a callback to be executed based on a regex pattern
*
* @param htp the initialized evhtp_t
* @param pattern a POSIX compat regular expression
* @param cb the function to be executed
* @param arg user-defined argument passed to the callback
*
* @return evhtp_callback_t * on success, NULL on error
*/
  1. ifndef EVHTP_DISABLE_REGEX

evhtp_callback_t * evhtp_set_regex_cb(evhtp_t * htp, const char * pattern, evhtp_callback_cb cb, void * arg);

  1. endif

/**

* @brief sets a callback to to be executed on simple glob/wildcard patterns
*        this is useful if the app does not care about what was matched, but
*        just that it matched. This is technically faster than regex.
*
* @param htp
* @param pattern wildcard pattern, the '*' can be set at either or both the front or end.
* @param cb
* @param arg
*
* @return
*/

evhtp_callback_t * evhtp_set_glob_cb(evhtp_t * htp, const char * pattern, evhtp_callback_cb cb, void * arg); </source> 지정된 경로가 호출되었을 때 실행 될 콜백 함수를 지정한다. evhtp_set_regex_cb() 함수는 정규 표현식 경로를 지원하지만, libevhtp 빌드시, 정규 표현식 옵션이 설정되어 있어야 한다. evhtp_set_glob_cb() 함수는 globbing 을 지원한다.

  • Example

<source lang=c> void testcb(evhtp_request_t *req, void *a) {

   const char *str = a;
   
   evbuffer_add_printf(req->buffer_out, "%s", str);
   evhtp_send_reply(req, EVHTP_RES_OK);

}

evhtp_t *htp = evhtp_new(evbase, NULL);

evhtp_callback_t *cb1 = evhtp_set_cb(htp, "/simple/", testcb, "simple"); evhtp_callback_t *cb2 = evhtp_set_regex_cb(htp, "^(/anything/).*", testcb, "simple"); evhtp_callback_t *cb3 = evhtp_set_glob_cb(htp, "/glob/", testcb, "simple"); </source>

connection hook

  • Interface

<source lang=c> /**

* @brief sets a callback hook for either a connection or a path/regex .
*
* A user may set a variety of hooks either per-connection, or per-callback.
* This allows the developer to hook into various parts of the request processing
* cycle.
*
* a per-connection hook can be set at any time, but it is recommended to set these
* during either a pre-accept phase, or post-accept phase. This allows a developer
* to set hooks before any other hooks are called.
*
* a per-callback hook works differently. In this mode a developer can setup a set
* of hooks prior to starting the event loop for specific callbacks. For example
* if you wanted to hook something ONLY for a callback set by evhtp_set_cb or
* evhtp_set_regex_cb this is the method of doing so.
*
* per-callback example:
*
* evhtp_callback_t * cb = evhtp_set_regex_cb(htp, "/anything/(.*)", default_cb, NULL);
*
* evhtp_set_hook(&cb->hooks, evhtp_hook_on_headers, anything_headers_cb, NULL);
*
* evhtp_set_hook(&cb->hooks, evhtp_hook_on_fini, anything_fini_cb, NULL);
*
* With the above example, once libevhtp has determined that it has a user-defined
* callback for /anything/.*; anything_headers_cb will be executed after all headers
* have been parsed, and anything_fini_cb will be executed before the request is
* free()'d.
*
* The same logic applies to per-connection hooks, but it should be noted that if
* a per-callback hook is set, the per-connection hook will be ignored.
*
* @param hooks double pointer to the evhtp_hooks_t structure
* @param type the hook type
* @param cb the callback to be executed.
* @param arg optional argument which is passed when the callback is executed
*
* @return 0 on success, -1 on error (if hooks is NULL, it is allocated)
*/

int evhtp_set_hook(evhtp_hooks_t ** hooks, evhtp_hook_type type, evhtp_hook cb, void * arg);

/**

* @brief remove a specific hook from being called.
*
* @param hooks
* @param type
*
* @return
*/

int evhtp_unset_hook(evhtp_hooks_t ** hooks, evhtp_hook_type type);

/**

* @brief removes all hooks.
*
* @param hooks
*
* @return
*/

int evhtp_unset_all_hooks(evhtp_hooks_t ** hooks);

/**

* @brief sets a callback which is called if no other callbacks are matched
*
* @param htp the initialized evhtp_t
* @param cb  the function to be executed
* @param arg user-defined argument passed to the callback
*/

void evhtp_set_gencb(evhtp_t * htp, evhtp_callback_cb cb, void * arg); void evhtp_set_pre_accept_cb(evhtp_t * htp, evhtp_pre_accept_cb, void * arg); void evhtp_set_post_accept_cb(evhtp_t * htp, evhtp_post_accept_cb, void * arg);

/**

* @brief types associated with where a developer can hook into
*        during the request processing cycle.
*/

enum evhtp_hook_type {

   evhtp_hook_on_header,       /**< type which defines to hook after one header has been parsed */
   evhtp_hook_on_headers,      /**< type which defines to hook after all headers have been parsed */
   evhtp_hook_on_path,         /**< type which defines to hook once a path has been parsed */
   evhtp_hook_on_read,         /**< type which defines to hook whenever the parser recieves data in a body */
   evhtp_hook_on_request_fini, /**< type which defines to hook before the request is free'd */
   evhtp_hook_on_connection_fini,
   evhtp_hook_on_new_chunk,
   evhtp_hook_on_chunk_complete,
   evhtp_hook_on_chunks_complete,
   evhtp_hook_on_headers_start,
   evhtp_hook_on_error,        /**< type which defines to hook whenever an error occurs */
   evhtp_hook_on_hostname,
   evhtp_hook_on_write

}; </source> 각각의 HTTP 연결마다 호출되는 Hook 콜백 함수를 설정한다. evhtp_set_gencb(), evhtp_set_pre_accept_cb(), evhtp_set_post_accept_cb() 함수들은 default callback 함수들을 지정한다.


Listen 소켓 설정/해제

  • Interface

<source lang=c> /**

* @brief bind to a socket, optionally with specific protocol support
*        formatting. The addr can be defined as one of the following:
*          ipv6:<ipv6addr> for binding to an IPv6 address.
*          unix:<named pipe> for binding to a unix named socket
*          ipv4:<ipv4addr> for binding to an ipv4 address
*        Otherwise the addr is assumed to be ipv4.
*
* @param htp
* @param addr
* @param port
* @param backlog
*
* @return
*/

int evhtp_bind_socket(evhtp_t * htp, const char * addr, uint16_t port, int backlog);

/**

* @brief stops the listening socket.
*
* @param htp
*/

void evhtp_unbind_socket(evhtp_t * htp); </source> Listen 주소를 설정/해제한다. 주소 설정 시, 자동으로 주소 타입을 파싱해서 알맞은 소켓 타입으로 생성한 후, listen 한다. "0.0.0.0" 설정시, localhost 주소를 listen 한다.

  • Example

<source lang=c> evhtp_bind_socket(htp, "0.0.0.0", 8081, 1024);

evhtp_unbind_socket(htp); </source>

evhtp_send_reply

HTTP Request 를 보낸 클라이언트로 응답값을 전송한다. <source lang=c> void evhtp_send_reply(evhtp_request_t * request, evhtp_res code); void evhtp_send_reply_start(evhtp_request_t * request, evhtp_res code); void evhtp_send_reply_body(evhtp_request_t * request, evbuf_t * buf); void evhtp_send_reply_end(evhtp_request_t * request); </source>

사용가능한 응답값은 다음과 같다. <source lang=c>

  1. define EVHTP_RES_ERROR 0
  2. define EVHTP_RES_PAUSE 1
  3. define EVHTP_RES_FATAL 2
  4. define EVHTP_RES_USER 3
  5. define EVHTP_RES_DATA_TOO_LONG 4
  6. define EVHTP_RES_OK 200
  1. define EVHTP_RES_100 100
  2. define EVHTP_RES_CONTINUE 100
  3. define EVHTP_RES_SWITCH_PROTO 101
  4. define EVHTP_RES_PROCESSING 102
  5. define EVHTP_RES_URI_TOOLONG 122
  1. define EVHTP_RES_200 200
  2. define EVHTP_RES_CREATED 201
  3. define EVHTP_RES_ACCEPTED 202
  4. define EVHTP_RES_NAUTHINFO 203
  5. define EVHTP_RES_NOCONTENT 204
  6. define EVHTP_RES_RSTCONTENT 205
  7. define EVHTP_RES_PARTIAL 206
  8. define EVHTP_RES_MSTATUS 207
  9. define EVHTP_RES_IMUSED 226
  1. define EVHTP_RES_300 300
  2. define EVHTP_RES_MCHOICE 300
  3. define EVHTP_RES_MOVEDPERM 301
  4. define EVHTP_RES_FOUND 302
  5. define EVHTP_RES_SEEOTHER 303
  6. define EVHTP_RES_NOTMOD 304
  7. define EVHTP_RES_USEPROXY 305
  8. define EVHTP_RES_SWITCHPROXY 306
  9. define EVHTP_RES_TMPREDIR 307
  1. define EVHTP_RES_400 400
  2. define EVHTP_RES_BADREQ 400
  3. define EVHTP_RES_UNAUTH 401
  4. define EVHTP_RES_PAYREQ 402
  5. define EVHTP_RES_FORBIDDEN 403
  6. define EVHTP_RES_NOTFOUND 404
  7. define EVHTP_RES_METHNALLOWED 405
  8. define EVHTP_RES_NACCEPTABLE 406
  9. define EVHTP_RES_PROXYAUTHREQ 407
  10. define EVHTP_RES_TIMEOUT 408
  11. define EVHTP_RES_CONFLICT 409
  12. define EVHTP_RES_GONE 410
  13. define EVHTP_RES_LENREQ 411
  14. define EVHTP_RES_PRECONDFAIL 412
  15. define EVHTP_RES_ENTOOLARGE 413
  16. define EVHTP_RES_URITOOLARGE 414
  17. define EVHTP_RES_UNSUPPORTED 415
  18. define EVHTP_RES_RANGENOTSC 416
  19. define EVHTP_RES_EXPECTFAIL 417
  20. define EVHTP_RES_IAMATEAPOT 418
  1. define EVHTP_RES_500 500
  2. define EVHTP_RES_SERVERR 500
  3. define EVHTP_RES_NOTIMPL 501
  4. define EVHTP_RES_BADGATEWAY 502
  5. define EVHTP_RES_SERVUNAVAIL 503
  6. define EVHTP_RES_GWTIMEOUT 504
  7. define EVHTP_RES_VERNSUPPORT 505
  8. define EVHTP_RES_BWEXEED 509

</source>

Samples

test_basic

  • test_basic.c

<source lang=c>

  1. include <stdio.h>
  2. include <stdlib.h>
  3. include <string.h>
  4. include <stdint.h>
  5. include <errno.h>
  6. include <evhtp.h>

void testcb(evhtp_request_t *req, void *a) {

   const char *str = a;
   
   evbuffer_add_printf(req->buffer_out, "%s", str);
   evhtp_send_reply(req, EVHTP_RES_OK);

}

int main(int argc, char **argv) {

   evbase_t *evbase    = event_base_new();
   evhtp_t *htp        = evhtp_new(evbase, NULL);
   
   evhtp_set_cb(htp, "/simple/", testcb, "simple");
   evhtp_set_cb(htp, "/1/ping", testcb, "one");
   evhtp_set_cb(htp, "/1/ping.json", testcb, "two");
  1. ifndef EVHTP_DISABLE_EVTHR
   evhtp_use_threads(htp, NULL, 4, NULL);
  1. endif
   evhtp_bind_socket(htp, "0.0.0.0", 8081, 1024);
   
   event_base_loop(evbase, 0);
   
   evhtp_unbind_socket(htp);
   evhtp_free(htp);
   event_base_free(evbase);
   
   return 0;

} </source>

References

<references />