libmicrohttpd2

HTTP server C library (MHD 2.x, alpha)
Log | Files | Refs | README | LICENSE

migration.inc (16592B)


      1 This chapter discusses how to convert an existing codebase that uses
      2 GNU libmicrohttpd 1.x (or 0.x) to the GNU libmicrohttpd 2.x API. It
      3 was written based on the experience of migrating GNU Taler's Sync
      4 service to the new API. It should cover @emph{most} of the important
      5 steps, but may omit some details. In general, there are no
      6 @emph{subtle} steps needed to migrate a code base: if the new code
      7 compiles, it most likely is OK as there is no function that kept is
      8 name but changed semantics, and the new API is generally simply safer
      9 to use and has fewer corner cases to consider.
     10 
     11 @node libmicrohttpd-configure
     12 @section Compile-time testing for the MHD 2.x dependency
     13 @cindex autoconf
     14 @cindex automake
     15 @cindex pkg-config
     16 
     17 Typically, the first step for migrating to the new API is to
     18 add (or replace) the detection logic for the MHD library in
     19 the build system. With GNU autotools and @code{pkg-config},
     20 the following snippet could be placed in @code{configure.ac}
     21 to detect libmicrohttpd2:
     22 
     23 @verbatim
     24 AC_ARG_WITH([microhttpd2],
     25   [AS_HELP_STRING([--with-microhttpd2=PFX],
     26                   [base of libmicrohttpd2 installation])],
     27   [SAVE_PKG_PATH="$PKG_CONFIG_PATH"
     28    PKG_CONFIG_PATH="${withval}/lib/pkgconfig"
     29    export PKG_CONFIG_PATH
     30    PKG_CHECK_MODULES([MHD], [libmicrohttpd2 >= 2.0.0], [libmhd2=1], [libmhd2=0])
     31    PKG_CONFIG_PATH="$SAVE_PKG_PATH"],
     32   [PKG_CHECK_MODULES([MHD], [libmicrohttpd2 >= 2.0.0], [libmhd2=1], [libmhd2=0])])
     33 
     34 # Do this only if you require MHD2:
     35 AS_IF([test "x$libmhd2" = "x0"],
     36   [AC_MSG_ERROR([This program requires libmicrohttpd >= 2.0.0])])
     37 
     38 # Alternatively, do this to conditionally compile MHD2 code:
     39 AM_CONDITIONAL([HAVE_MHD2], [test "x$libmhd2" = "x1"])
     40 
     41 # and/or use this to use ifdef to compile code only when MHD2 is available:
     42 AC_DEFINE_UNQUOTED([HAVE_MHD2], [$libmhd2],
     43                    [Define to 1 if libmicrohttpd2 is available])
     44 @end verbatim
     45 
     46 If you do not want to rely on @code{pkg-config}, you can use
     47 a more direct test:
     48 
     49 @verbatim
     50 # check for libmicrohttpd
     51 AC_MSG_CHECKING([for microhttpd2])
     52 AC_ARG_WITH([microhttpd2],
     53             [AS_HELP_STRING([--with-microhttpd2=PFX], [base of libmicrohttpd2 installation])],
     54             [AC_MSG_RESULT([given as $with_microhttpd2])],
     55             [AC_MSG_RESULT([not given])
     56              with_microhttpd2=yes])
     57 AS_CASE([$with_microhttpd2],
     58         [yes],,
     59         [no],,
     60         [LDFLAGS="-L$with_microhttpd2/lib $LDFLAGS"
     61          CPPFLAGS="-I$with_microhttpd2/include $CPPFLAGS"])
     62 # This will set HAVE_MHD2 as above for conditional compilation
     63 MHD2_VERSION_AT_LEAST([2.0.0])
     64 @end verbatim
     65 
     66 The @code{MHD2_VERSION_AT_LEAST} is an M4 macro available in the
     67 @code{mhd2.m4} file as part of the GNU libmicrohttpd2 library which
     68 implements a test for the specific MHD version. You may need to copy
     69 the @code{mhd2.m4} file into your @code{m4/} directory so that GNU
     70 autoconf can find it.
     71 
     72 @cindex meson
     73 
     74 When using @code{Meson} as the buidl system, a dependency test
     75 would typically look like this:
     76 
     77 @verbatim
     78 mhd2_dep = dependency('libmicrohttpd2', required : false)
     79 if not mhd2_dep.found()
     80   mhd_dep2 = cc.find_library('microhttpd2', required : false)
     81 endif
     82 @end verbatim
     83 
     84 Adjust the @code{required} argument to
     85 @code{true} if MHD2 is a mandatory dependency.
     86 
     87 Naturally, there are various variations of the above that
     88 could be used to detect MHD2, so these are merely examples
     89 to get started.
     90 
     91 
     92 @node libmicrohttpd-include
     93 @section Changes to includes
     94 @cindex include
     95 
     96 The obvious change here is to change
     97 @verbatim
     98 #include <microhttpd.h>
     99 @end verbatim
    100 
    101 to
    102 
    103 @verbatim
    104 #include <microhttpd2.h>
    105 @end verbatim
    106 
    107 However, there might be one more subtle consideration, which
    108 is that in the previous version the @code{microhttpd.h} header
    109 required the application to possibly include various system
    110 header first. That requirement was lifted with MHD2, so this
    111 could be an opportunity to review whether some other includes
    112 are still necessary and possibly remove them.
    113 
    114 @node libmicrohttpd-constant-replacement
    115 @section Global constants to migrate
    116 
    117 Globally, the following constants must be renamed. The
    118 constants in this list are 1:1 replacements and thus
    119 a simple global rename operation should be safe:
    120 
    121 @table @code
    122 @item MHD_HEADER_KIND
    123 must be replaced by @code{MHD_VK_HEADER}.
    124 
    125 @item MHD_COOKIE_KIND
    126 must be replaced by @code{MHD_VK_COOKIE}.
    127 
    128 @item MHD_POSTDATA_KIND
    129 must be replaced by @code{MHD_VK_POSTDATA}.
    130 
    131 @item MHD_FOOTER_KIND
    132 must be replaced by @code{MHD_VK_FOOTER}.
    133 
    134 @item MHD_GET_ARGUMENT_KIND
    135 must be replaced by @code{MHD_VK_GET_ARGUMENT}.
    136 @c FIXME: under discussion to change away from GET!
    137 
    138 @item MHD_HTTP_REQUEST_ENTITY_TOO_LARGE
    139 must be replaced by @code{MHD_HTTP_STATUS_CONTENT_TOO_LARGE}.
    140 
    141 @end table
    142 
    143 
    144 
    145 
    146 @node libmicrohttpd-migrate-start-daemon
    147 @section Changes to @code{MHD_start_daemon()}
    148 
    149 The main change to @code{MHD_start_daemon} is to rename the
    150 call to @code{MHD_daemon_create}. The existing argument of
    151 type @code{MHD_AccessHandlerCallback} should be changed
    152 into the new @code{MHD_RequestCallback}. All other arguments
    153 (explicit and from the varargs)
    154 need to be set via @ref{MHD_DAEMON_SET_OPTIONS} and related
    155 APIs. @xref{libmicrohttpd-daemon-options-setting}
    156 Finally, after setting the options, the application
    157 must call @ref{MHD_daemon_start}. Thus, the existing
    158 @code{MHD_start_daemon} is replaced by three main calls:
    159 
    160 @itemize
    161 @item @ref{MHD_daemon_create}
    162 @item @ref{MHD_daemon_set_options}
    163 @item @ref{MHD_daemon_start}
    164 @end itemize
    165 
    166 There are a few minor changes to be made to the related API calls
    167 to quiesce and destroy the daemon: the functions
    168 @code{MHD_stop_daemon()} and @code{MHD_quiesce_daemon()} were renamed
    169 to @code{MHD_daemon_destroy()} and @code{MHD_daemon_quiesce()}
    170 respectively. Nevertheless, the behavior is completely unchanged,
    171 so applications only need to rename the calls.
    172 
    173 @node libmicrohttpd-migrate-loop
    174 @section Migrating an external event loop
    175 
    176 When migrating an external event loop, the first significant change
    177 is that one must expicitly set an option with a callback for MHD
    178 to call on changes to the set of watched sockets.  Previously, the
    179 event loop could query MHD using @code{MHD_get_fdset()} (and related
    180 APIs). Now, the application must instead configure the daemon with
    181 a callback:
    182 
    183 @verbatim
    184   MHD_DAEMON_SET_OPTIONS (
    185     daemon,
    186     MHD_D_OPTION_WM_EXTERNAL_EVENT_LOOP_CB_LEVEL (
    187       &socket_registration_update,
    188       NULL));
    189 @end verbatim
    190 
    191 For our example, the application will define
    192 @code{MHD_APP_SOCKET_CNTX_TYPE} to a @code{struct ScoketContext}.
    193 Inside of that structure, the application will track its state for
    194 the external event loop:
    195 
    196 @verbatim
    197 #define MHD_APP_SOCKET_CNTX_TYPE struct SocketContext
    198 #include <microhttpd2.h>
    199 
    200 struct SocketContext {
    201   // Note: add other data specific to the event loop!
    202   struct MHD_EventUpdateContext *ecb_cntx;
    203   MHD_Socket fd;
    204 };
    205 @end verbatim
    206 
    207 In the respective callback (here @code{socket_registration_update()})
    208 the application must then update its state for the event loop:
    209 
    210 @verbatim
    211 static MHD_APP_SOCKET_CNTX_TYPE *
    212 socket_registration_update (
    213   void *cls,
    214   MHD_Socket fd,
    215   enum MHD_FdState watch_for,
    216   MHD_APP_SOCKET_CNTX_TYPE *app_cntx_old,
    217   struct MHD_EventUpdateContext *ecb_cntx)
    218 {
    219   struct SocketContext *sc;
    220 
    221   if (NULL == app_cntx_old)
    222   {
    223     sc = malloc (sizeof (struct SocketContext));
    224     sc->ecb_cntx = ecb_cntx;
    225     sc->fd = fd;
    226   }
    227   else
    228   {
    229     sc = app_cntx_old;
    230   }
    231   if (MHD_FD_STATE_NONE == watch_for)
    232   {
    233     // clean up everything in 'app_cntx_old'
    234     free (app_cntx_old);
    235     return NULL;
    236   }
    237   if (MHD_FD_STATE_RECV & watch_for)
    238   {
    239     // Update 'app_cntx_old' to notify on read-ready
    240     // (e.g. FD_SET (fd, readfds))
    241   }
    242   else
    243   {
    244     // Update 'app_cntx_old' to not notify on read-ready
    245     // (e.g. FD_CLEAR (fd, readfds))
    246   }
    247   if (MHD_FD_STATE_SEND & watch_for)
    248   {
    249     // Update 'app_cntx_old' to notify on write-ready
    250     // (e.g. FD_SET (fd, writefds))
    251   }
    252   else
    253   {
    254     // Update 'app_cntx_old' to not notify on write-ready
    255     // (e.g. FD_CLEAR (fd, writefds))
    256   }
    257   if (MHD_FD_STATE_EXCEPT & watch_for)
    258   {
    259     // Update 'app_cntx_old' to notify on exceptions
    260     // (e.g. FD_SET (fd, exceptfds))
    261   }
    262   else
    263   {
    264     // Update 'app_cntx_old' to not notify on exceptions
    265     // (e.g. FD_CLEAR (fd, exceptfds))
    266   }
    267   return sc;
    268 }
    269 @end verbatim
    270 
    271 Finally, when the external event loop detects that the socket is
    272 ready for some operation, it must then signal that the respective
    273 operation is ready:
    274 
    275 @verbatim
    276 struct SocketContext *sc = ...;
    277 
    278 MHD_daemon_event_update (daemon,
    279                          sc->ecb_cntx,
    280                          MHD_FD_STATE_RECV);
    281 @end verbatim
    282 
    283 Naturally, @code{MHD_FD_STATE_RECV} should be replaced by the
    284 correct set of operations that are ready.
    285 
    286 Finally, the application needs to take care to give MHD a chance
    287 to actually process events. This must be done every time either
    288 the global timeout expired, or @code{MHD_daemon_event_update()}
    289 was called:
    290 
    291 @verbatim
    292 void
    293 run_daemon (void)
    294 {
    295   uint_fast64_t next_max_wait;
    296 
    297   MHD_daemon_process_reg_events (daemon,
    298                                  &next_max_wait));
    299   // wait next_max_wait *or* FD ready before calling
    300   // again
    301 }
    302 @end verbatim
    303 
    304 There is a special case to consider, namely when
    305 @var{next_max_wait} is set to @code{MHD_WAIT_INDEFINITELY}
    306 then the timeout is "forever" and the application should only
    307 wait on the socket states.
    308 
    309 A complete example for this type of external event loop migration
    310 using the GNUnet event loop can be found at
    311 @url{https://git.taler.net/exchange.git/tree/src/mhd}. Here, the
    312 @file{mhd_run.c} file contains the MHD v1.0 logic, and @file{mhd2_run.c}
    313 contains the equivalent MHD v2.0 logic.  The external API of the
    314 module is completely unchanged.
    315 
    316 @node libmicrohttpd-migrate-request-handling
    317 @section Migrating request handling
    318 
    319 The first change to request handling is to replace all existing uses
    320 of @code{struct MHD_Connection} with the new @code{struct
    321 MHD_Request}.  While @code{struct MHD_Connection} still exists in the
    322 new API, it represents something else and thus legacy code should be
    323 transformed by first changing all @code{struct MHD_Connection} to
    324 @code{struct MHD_Request}.
    325 
    326 When inspecting the HTTP request, the following substitutions
    327 should be made:
    328 
    329 @table @code
    330 @item MHD_lookup_connection_value
    331 replaced by @ref{MHD_request_get_value}; note the slight change
    332 in the return value type.
    333 
    334 @end table
    335 
    336 Applications that previously used the
    337 @var{req_cls} argument of the
    338 @code{MHD_AccessHandlerCallback} must now use
    339 @ref{MHD_REQUEST_INFO_FIXED_APP_CONTEXT} with
    340 @ref{MHD_request_get_info_fixed} to get the
    341 same @code{void **} from inside the
    342 @ref{MHD_RequestInfoFixedData}.
    343 @c FIXME: specify which member (to be renamed...)
    344 
    345 
    346 @node libmicrohttpd-migrate-upload-handling
    347 @section Migrating upload handling
    348 
    349 When handling requests with a body, previous code had to return
    350 @code{MHD_YES} from the main callback on the first call and
    351 then receive the upload data incrementally in subsequent calls.
    352 In MHD2, the application must instead return an action
    353 generated from calls to @ref{MHD_action_process_upload},
    354 @ref{MHD_action_process_upload_full}, or
    355 @ref{MHD_action_process_upload_inc}.
    356 
    357 Explicitly checking the "Content-Length" request header to ensure
    358 that the upload is not too big is no longer necessary as MHD
    359 now provides the request body length explicitly to the main
    360 callback.
    361 
    362 When returning a response from an upload, calls to
    363 @code{MHD_queue_response} must be replaced by
    364 returning the action created by
    365 @code{MHD_upload_action_from_response}.
    366 
    367 
    368 @node libmicrohttpd-migrate-suspend-handling
    369 @section Migrating suspended requests handling
    370 
    371 Previous calls to @code{MHD_suspend_request} must be
    372 replaced by returning an action from
    373 @ref{MHD_action_suspend}, @ref{MHD_upload_action_suspend}
    374 or @ref{MHD_DCC_action_suspend}.
    375 
    376 Previous calls to @code{MHD_resume_request} must be
    377 replaced by calls to @ref{MHD_request_resume}.
    378 
    379 
    380 
    381 @node libmicrohttpd-migrate-response-generation
    382 @section Migrating response generation
    383 
    384 The main change in response generation is that with MHD2 you
    385 must always already provide the HTTP status code when creating
    386 a response. Thus, functions that could previously merely create
    387 the response from headers and body must be modified to also
    388 take the HTTP status code. Also, previously applications
    389 may have used a simple @code{unsigned int} to represent the
    390 HTTP status code. This should be changed to the new
    391 @code{enum MHD_HTTP_StatusCode}.
    392 
    393 The names for the HTTP status code constants changed, all constants
    394 that started with @code{MHD_HTTP_} need to be updated to use the new
    395 @code{MHD_HTTP_STATUS_} prefix.  Note that this only applies
    396 to the HTTP status constants: the constants starting with the
    397 @code{MHD_HTTP_HEADER_} prefix must not be changed!
    398 
    399 Other than that, the main change is that the functions
    400 to generate responses were renamed, the new functions
    401 all start with @code{MHD_response_from_}. All previous
    402 functions have a clear match in the new API. The following
    403 table contains a short cheat-list:
    404 
    405 @table @code
    406 @item MHD_add_response_header
    407 replaced by @ref{MHD_response_add_header}; note the slight change
    408 in the return value type (now @code{MHD_SC_OK} (aka 0) is returned
    409 instead of @code{MHD_YES} (aka 1) for success).
    410 
    411 @item MHD_create_response_from_buffer
    412 replaced by @ref{MHD_response_from_buffer} and convenience
    413 wrappers @ref{MHD_response_from_buffer_static},
    414 @ref{MHD_response_from_buffer_copy},
    415 @ref{MHD_response_from_empty}.
    416 
    417 @item MHD_create_response_from_fd
    418 replaced by @ref{MHD_response_from_fd} (with additional @var{offset}
    419 argument).
    420 
    421 @end table
    422 
    423 Finally, to return a response, the call to @code{MHD_queue_response()}
    424 will need to be replaced by a call to
    425 @code{MHD_action_from_response()} or
    426 @code{MHD_upload_action_from_response()} depending on which callback
    427 is returning the response.  After calling
    428 @code{MHD_upload_action_from_response()} the calls to
    429 @code{MHD_destroy_response()} should be removed, @emph{unless}
    430 @ref{MHD_R_OPTION_REUSABLE} was set on the response.
    431 Calls to @code{MHD_destroy_response()} on code paths that do not
    432 lead to the response being turned into an action should be
    433 replaced by @code{MHD_response_destroy()}.
    434 
    435 @node libmicrohttpd-migrate-post-processor
    436 @section Migrating post processing
    437 
    438 The main change for post-processing is that instead of taking the
    439 upload data from the main callback and incrementally feeding it into a
    440 @code{struct MHD_PostProcessor}, the application should now simply
    441 create a @ref{MHD_Action} via @ref{MHD_action_parse_post}. This
    442 effectively combines creating the post processor, passing it the
    443 uploaded data and receiving the results. The new API is more powerful,
    444 so if the upload is known to be small enough (like for a simple HTML
    445 form without file uploads) the application no longer needs to deal
    446 with incremental value uploads and can simply inspect all uploaded
    447 values in the @code{MHD_PostDataFinished} callback using
    448 @ref{MHD_request_get_value} (and related APIs) with the
    449 @code{MHD_VK_POSTDATA}.
    450 
    451 
    452 @node libmicrohttpd-migrate-notifications
    453 @section Changes to notification callbacks
    454 
    455 The @code{MHD_OPTION_NOTIFY_COMPLETED} was replaced
    456 with the @code{MHD_R_OTION_TERMINATION_CALLBACK} which
    457 must now be set on each request instead of once per
    458 daemon.
    459 
    460 
    461 @node libmicrohttpd-migrate-introspection
    462 @section Changes to introspection calls
    463 
    464 These are pretty simple substitutions:
    465 
    466 @table @code
    467 @item MHD_get_request_info
    468 replaced by @ref{MHD_request_get_info_fixed} or
    469 @ref{MHD_request_get_info_dynamic} depending on the
    470 type of information requested
    471 
    472 @item MHD_RequestInfo
    473 replaced by @ref{MHD_RequestInfoFixedData} or
    474 @ref{MHD_RequestInfoDynamicData} depending on the
    475 type of information requested
    476 
    477 @item MHD_REQUEST_INFO_
    478 replaced by @code{MHD_REQUEST_INFO_FIXED_} or
    479 @code{MHD_REQUEST_INFO_DYNAMIC_} depending on the
    480 type of information requested;
    481 see @ref{libmicrohttpd2-info request,,request introspection}
    482 
    483 @item MHD_get_daemon_info
    484 replaced by @ref{MHD_daemon_get_info_fixed} or
    485 @ref{MHD_daemon_get_info_dynamic} depending on the
    486 type of information daemoned
    487 
    488 @item MHD_DaemonInfo
    489 replaced by @ref{MHD_DaemonInfoFixedData} or
    490 @ref{MHD_DaemonInfoDynamicData} depending on the
    491 type of information daemoned
    492 
    493 @item MHD_DAEMON_INFO_
    494 replaced by @code{MHD_DAEMON_INFO_FIXED_} or
    495 @code{MHD_DAEMON_INFO_DYNAMIC_} depending on the
    496 type of information daemoned;
    497 see @ref{libmicrohttpd2-info daemon,,daemon introspection}
    498 
    499 @end table
    500 
    501 The @code{MHD_is_feature_supported} function is replaced by the new
    502 @ref{libmicrohttpd2-info library,,library introspection} API.