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.