1 module soup.Server; 2 3 private import gio.IOStream; 4 private import gio.Socket: GIOSocket = Socket; 5 private import gio.SocketAddress; 6 private import glib.ConstructionException; 7 private import glib.ErrorG; 8 private import glib.GException; 9 private import glib.ListSG; 10 private import glib.MainContext; 11 private import glib.Str; 12 private import gobject.ObjectG; 13 private import gobject.Signals; 14 private import soup.AuthDomain; 15 private import soup.ClientContext; 16 private import soup.Message; 17 private import soup.Socket; 18 private import soup.c.functions; 19 public import soup.c.types; 20 private import std.algorithm; 21 22 23 /** 24 * #SoupServer implements a simple HTTP server. 25 * 26 * (The following documentation describes the current #SoupServer API, 27 * available in <application>libsoup</application> 2.48 and later. See 28 * the section "<link linkend="soup-server-old-api">The Old SoupServer 29 * Listening API</link>" in the server how-to documentation for 30 * details on the older #SoupServer API.) 31 * 32 * To begin, create a server using soup_server_new(). Add at least one 33 * handler by calling soup_server_add_handler() or 34 * soup_server_add_early_handler(); the handler will be called to 35 * process any requests underneath the path you pass. (If you want all 36 * requests to go to the same handler, just pass "/" (or %NULL) for 37 * the path.) 38 * 39 * When a new connection is accepted (or a new request is started on 40 * an existing persistent connection), the #SoupServer will emit 41 * #SoupServer::request-started and then begin processing the request 42 * as described below, but note that once the message is assigned a 43 * #SoupMessage:status-code, then callbacks after that point will be 44 * skipped. Note also that it is not defined when the callbacks happen 45 * relative to various #SoupMessage signals. 46 * 47 * Once the headers have been read, #SoupServer will check if there is 48 * a #SoupAuthDomain (qv) covering the Request-URI; if so, and if the 49 * message does not contain suitable authorization, then the 50 * #SoupAuthDomain will set a status of %SOUP_STATUS_UNAUTHORIZED on 51 * the message. 52 * 53 * After checking for authorization, #SoupServer will look for "early" 54 * handlers (added with soup_server_add_early_handler()) matching the 55 * Request-URI. If one is found, it will be run; in particular, this 56 * can be used to connect to signals to do a streaming read of the 57 * request body. 58 * 59 * (At this point, if the request headers contain "<literal>Expect: 60 * 100-continue</literal>", and a status code has been set, then 61 * #SoupServer will skip the remaining steps and return the response. 62 * If the request headers contain "<literal>Expect: 63 * 100-continue</literal>" and no status code has been set, 64 * #SoupServer will return a %SOUP_STATUS_CONTINUE status before 65 * continuing.) 66 * 67 * The server will then read in the response body (if present). At 68 * this point, if there are no handlers at all defined for the 69 * Request-URI, then the server will return %SOUP_STATUS_NOT_FOUND to 70 * the client. 71 * 72 * Otherwise (assuming no previous step assigned a status to the 73 * message) any "normal" handlers (added with 74 * soup_server_add_handler()) for the message's Request-URI will be 75 * run. 76 * 77 * Then, if the path has a WebSocket handler registered (and has 78 * not yet been assigned a status), #SoupServer will attempt to 79 * validate the WebSocket handshake, filling in the response and 80 * setting a status of %SOUP_STATUS_SWITCHING_PROTOCOLS or 81 * %SOUP_STATUS_BAD_REQUEST accordingly. 82 * 83 * If the message still has no status code at this point (and has not 84 * been paused with soup_server_pause_message()), then it will be 85 * given a status of %SOUP_STATUS_INTERNAL_SERVER_ERROR (because at 86 * least one handler ran, but returned without assigning a status). 87 * 88 * Finally, the server will emit #SoupServer::request-finished (or 89 * #SoupServer::request-aborted if an I/O error occurred before 90 * handling was completed). 91 * 92 * If you want to handle the special "*" URI (eg, "OPTIONS *"), you 93 * must explicitly register a handler for "*"; the default handler 94 * will not be used for that case. 95 * 96 * If you want to process https connections in addition to (or instead 97 * of) http connections, you can either set the 98 * %SOUP_SERVER_TLS_CERTIFICATE property when creating the server, or 99 * else call soup_server_set_ssl_certificate() after creating it. 100 * 101 * Once the server is set up, make one or more calls to 102 * soup_server_listen(), soup_server_listen_local(), or 103 * soup_server_listen_all() to tell it where to listen for 104 * connections. (All ports on a #SoupServer use the same handlers; if 105 * you need to handle some ports differently, such as returning 106 * different data for http and https, you'll need to create multiple 107 * #SoupServers, or else check the passed-in URI in the handler 108 * function.). 109 * 110 * #SoupServer will begin processing connections as soon as you return 111 * to (or start) the main loop for the current thread-default 112 * #GMainContext. 113 */ 114 public class Server : ObjectG 115 { 116 /** the main Gtk struct */ 117 protected SoupServer* soupServer; 118 119 /** Get the main Gtk struct */ 120 public SoupServer* getServerStruct(bool transferOwnership = false) 121 { 122 if (transferOwnership) 123 ownedRef = false; 124 return soupServer; 125 } 126 127 /** the main Gtk struct as a void* */ 128 protected override void* getStruct() 129 { 130 return cast(void*)soupServer; 131 } 132 133 /** 134 * Sets our main struct and passes it to the parent class. 135 */ 136 public this (SoupServer* soupServer, bool ownedRef = false) 137 { 138 this.soupServer = soupServer; 139 super(cast(GObject*)soupServer, ownedRef); 140 } 141 142 143 /** */ 144 public static GType getType() 145 { 146 return soup_server_get_type(); 147 } 148 149 /** 150 * Add a new client stream to the @server. 151 * 152 * Params: 153 * stream = a #GIOStream 154 * localAddr = the local #GSocketAddress associated with the @stream 155 * remoteAddr = the remote #GSocketAddress associated with the @stream 156 * 157 * Returns: %TRUE on success, %FALSE if the stream could not be 158 * accepted or any other error occurred (in which case @error will be 159 * set). 160 * 161 * Since: 2.50 162 * 163 * Throws: GException on failure. 164 */ 165 public bool acceptIostream(IOStream stream, SocketAddress localAddr, SocketAddress remoteAddr) 166 { 167 GError* err = null; 168 169 auto __p = soup_server_accept_iostream(soupServer, (stream is null) ? null : stream.getIOStreamStruct(), (localAddr is null) ? null : localAddr.getSocketAddressStruct(), (remoteAddr is null) ? null : remoteAddr.getSocketAddressStruct(), &err) != 0; 170 171 if (err !is null) 172 { 173 throw new GException( new ErrorG(err) ); 174 } 175 176 return __p; 177 } 178 179 /** 180 * Adds an authentication domain to @server. Each auth domain will 181 * have the chance to require authentication for each request that 182 * comes in; normally auth domains will require authentication for 183 * requests on certain paths that they have been set up to watch, or 184 * that meet other criteria set by the caller. If an auth domain 185 * determines that a request requires authentication (and the request 186 * doesn't contain authentication), @server will automatically reject 187 * the request with an appropriate status (401 Unauthorized or 407 188 * Proxy Authentication Required). If the request used the 189 * "100-continue" Expectation, @server will reject it before the 190 * request body is sent. 191 * 192 * Params: 193 * authDomain = a #SoupAuthDomain 194 */ 195 public void addAuthDomain(AuthDomain authDomain) 196 { 197 soup_server_add_auth_domain(soupServer, (authDomain is null) ? null : authDomain.getAuthDomainStruct()); 198 } 199 200 /** 201 * Adds an "early" handler to @server for requests under @path. Note 202 * that "normal" and "early" handlers are matched up together, so if 203 * you add a normal handler for "/foo" and an early handler for 204 * "/foo/bar", then a request to "/foo/bar" (or any path below it) 205 * will run only the early handler. (But if you add both handlers at 206 * the same path, then both will get run.) 207 * 208 * For requests under @path (that have not already been assigned a 209 * status code by a #SoupAuthDomain or a signal handler), @callback 210 * will be invoked after receiving the request headers, but before 211 * receiving the request body; the message's #SoupMessage:method and 212 * #SoupMessage:request-headers fields will be filled in. 213 * 214 * Early handlers are generally used for processing requests with 215 * request bodies in a streaming fashion. If you determine that the 216 * request will contain a message body, normally you would call 217 * soup_message_body_set_accumulate() on the message's 218 * #SoupMessage:request-body to turn off request-body accumulation, 219 * and connect to the message's #SoupMessage::got-chunk signal to 220 * process each chunk as it comes in. 221 * 222 * To complete the message processing after the full message body has 223 * been read, you can either also connect to #SoupMessage::got-body, 224 * or else you can register a non-early handler for @path as well. As 225 * long as you have not set the #SoupMessage:status-code by the time 226 * #SoupMessage::got-body is emitted, the non-early handler will be 227 * run as well. 228 * 229 * Params: 230 * path = the toplevel path for the handler 231 * callback = callback to invoke for requests under @path 232 * userData = data for @callback 233 * destroy = destroy notifier to free @user_data 234 * 235 * Since: 2.50 236 */ 237 public void addEarlyHandler(string path, SoupServerCallback callback, void* userData, GDestroyNotify destroy) 238 { 239 soup_server_add_early_handler(soupServer, Str.toStringz(path), callback, userData, destroy); 240 } 241 242 /** 243 * Adds a handler to @server for requests under @path. If @path is 244 * %NULL or "/", then this will be the default handler for all 245 * requests that don't have a more specific handler. (Note though that 246 * if you want to handle requests to the special "*" URI, you must 247 * explicitly register a handler for "*"; the default handler will not 248 * be used for that case.) 249 * 250 * For requests under @path (that have not already been assigned a 251 * status code by a #SoupAuthDomain, an early #SoupServerHandler, or a 252 * signal handler), @callback will be invoked after receiving the 253 * request body; the message's #SoupMessage:method, 254 * #SoupMessage:request-headers, and #SoupMessage:request-body fields 255 * will be filled in. 256 * 257 * After determining what to do with the request, the callback must at 258 * a minimum call soup_message_set_status() (or 259 * soup_message_set_status_full()) on the message to set the response 260 * status code. Additionally, it may set response headers and/or fill 261 * in the response body. 262 * 263 * If the callback cannot fully fill in the response before returning 264 * (eg, if it needs to wait for information from a database, or 265 * another network server), it should call soup_server_pause_message() 266 * to tell @server to not send the response right away. When the 267 * response is ready, call soup_server_unpause_message() to cause it 268 * to be sent. 269 * 270 * To send the response body a bit at a time using "chunked" encoding, 271 * first call soup_message_headers_set_encoding() to set 272 * %SOUP_ENCODING_CHUNKED on the #SoupMessage:response-headers. Then call 273 * soup_message_body_append() (or soup_message_body_append_buffer()) 274 * to append each chunk as it becomes ready, and 275 * soup_server_unpause_message() to make sure it's running. (The 276 * server will automatically pause the message if it is using chunked 277 * encoding but no more chunks are available.) When you are done, call 278 * soup_message_body_complete() to indicate that no more chunks are 279 * coming. 280 * 281 * Params: 282 * path = the toplevel path for the handler 283 * callback = callback to invoke for requests under @path 284 * userData = data for @callback 285 * destroy = destroy notifier to free @user_data 286 */ 287 public void addHandler(string path, SoupServerCallback callback, void* userData, GDestroyNotify destroy) 288 { 289 soup_server_add_handler(soupServer, Str.toStringz(path), callback, userData, destroy); 290 } 291 292 /** 293 * Add support for a WebSocket extension of the given @extension_type. 294 * When a WebSocket client requests an extension of @extension_type, 295 * a new #SoupWebsocketExtension of type @extension_type will be created 296 * to handle the request. 297 * 298 * You can also add support for a WebSocket extension to the server at 299 * construct time by using the %SOUP_SERVER_ADD_WEBSOCKET_EXTENSION property. 300 * Note that #SoupWebsocketExtensionDeflate is supported by default, use 301 * soup_server_remove_websocket_extension() if you want to disable it. 302 * 303 * Params: 304 * extensionType = a #GType 305 * 306 * Since: 2.68 307 */ 308 public void addWebsocketExtension(GType extensionType) 309 { 310 soup_server_add_websocket_extension(soupServer, extensionType); 311 } 312 313 /** 314 * Adds a WebSocket handler to @server for requests under @path. (If 315 * @path is %NULL or "/", then this will be the default handler for 316 * all requests that don't have a more specific handler.) 317 * 318 * When a path has a WebSocket handler registered, @server will check 319 * incoming requests for WebSocket handshakes after all other handlers 320 * have run (unless some earlier handler has already set a status code 321 * on the message), and update the request's status, response headers, 322 * and response body accordingly. 323 * 324 * If @origin is non-%NULL, then only requests containing a matching 325 * "Origin" header will be accepted. If @protocols is non-%NULL, then 326 * only requests containing a compatible "Sec-WebSocket-Protocols" 327 * header will be accepted. More complicated requirements can be 328 * handled by adding a normal handler to @path, and having it perform 329 * whatever checks are needed (possibly calling 330 * soup_server_check_websocket_handshake() one or more times), and 331 * setting a failure status code if the handshake should be rejected. 332 * 333 * Params: 334 * path = the toplevel path for the handler 335 * origin = the origin of the connection 336 * protocols = the protocols 337 * supported by this handler 338 * callback = callback to invoke for successful WebSocket requests under @path 339 * userData = data for @callback 340 * destroy = destroy notifier to free @user_data 341 */ 342 public void addWebsocketHandler(string path, string origin, string[] protocols, SoupServerWebsocketCallback callback, void* userData, GDestroyNotify destroy) 343 { 344 soup_server_add_websocket_handler(soupServer, Str.toStringz(path), Str.toStringz(origin), Str.toStringzArray(protocols), callback, userData, destroy); 345 } 346 347 /** 348 * Closes and frees @server's listening sockets. If you are using the 349 * old #SoupServer APIs, this also includes the effect of 350 * soup_server_quit(). 351 * 352 * Note that if there are currently requests in progress on @server, 353 * that they will continue to be processed if @server's #GMainContext 354 * is still running. 355 * 356 * You can call soup_server_listen(), etc, after calling this function 357 * if you want to start listening again. 358 */ 359 public void disconnect() 360 { 361 soup_server_disconnect(soupServer); 362 } 363 364 /** 365 * Gets @server's async_context, if you are using the old API. (With 366 * the new API, the server runs in the thread's thread-default 367 * #GMainContext, regardless of what this method returns.) 368 * 369 * This does not add a ref to the context, so you will need to ref it 370 * yourself if you want it to outlive its server. 371 * 372 * Deprecated: If you are using soup_server_listen(), etc, then 373 * the server listens on the thread-default #GMainContext, and this 374 * property is ignored. 375 * 376 * Returns: @server's #GMainContext, 377 * which may be %NULL 378 */ 379 public MainContext getAsyncContext() 380 { 381 auto __p = soup_server_get_async_context(soupServer); 382 383 if(__p is null) 384 { 385 return null; 386 } 387 388 return new MainContext(cast(GMainContext*) __p); 389 } 390 391 /** 392 * Gets @server's listening socket, if you are using the old API. 393 * 394 * You should treat this socket as read-only; writing to it or 395 * modifiying it may cause @server to malfunction. 396 * 397 * Deprecated: If you are using soup_server_listen(), etc, then use 398 * soup_server_get_listeners() to get a list of all listening sockets, 399 * but note that that function returns #GSockets, not #SoupSockets. 400 * 401 * Returns: the listening socket. 402 */ 403 public Socket getListener() 404 { 405 auto __p = soup_server_get_listener(soupServer); 406 407 if(__p is null) 408 { 409 return null; 410 } 411 412 return ObjectG.getDObject!(Socket)(cast(SoupSocket*) __p); 413 } 414 415 /** 416 * Gets @server's list of listening sockets. 417 * 418 * You should treat these sockets as read-only; writing to or 419 * modifiying any of these sockets may cause @server to malfunction. 420 * 421 * (Beware that in contrast to the old soup_server_get_listener(), this 422 * function returns #GSockets, not #SoupSockets.) 423 * 424 * Returns: a 425 * list of listening sockets. 426 */ 427 public ListSG getListeners() 428 { 429 auto __p = soup_server_get_listeners(soupServer); 430 431 if(__p is null) 432 { 433 return null; 434 } 435 436 return new ListSG(cast(GSList*) __p); 437 } 438 439 /** 440 * Gets the TCP port that @server is listening on, if you are using 441 * the old API. 442 * 443 * Deprecated: If you are using soup_server_listen(), etc, then use 444 * soup_server_get_uris() to get a list of all listening addresses. 445 * 446 * Returns: the port @server is listening on. 447 */ 448 public uint getPort() 449 { 450 return soup_server_get_port(soupServer); 451 } 452 453 /** 454 * Gets a list of URIs corresponding to the interfaces @server is 455 * listening on. These will contain IP addresses, not hostnames, and 456 * will also indicate whether the given listener is http or https. 457 * 458 * Note that if you used soup_server_listen_all(), the returned URIs 459 * will use the addresses <literal>0.0.0.0</literal> and 460 * <literal>::</literal>, rather than actually returning separate URIs 461 * for each interface on the system. 462 * 463 * Returns: a list of 464 * #SoupURIs, which you must free when you are done with it. 465 * 466 * Since: 2.48 467 */ 468 public ListSG getUris() 469 { 470 auto __p = soup_server_get_uris(soupServer); 471 472 if(__p is null) 473 { 474 return null; 475 } 476 477 return new ListSG(cast(GSList*) __p, true); 478 } 479 480 /** 481 * Checks whether @server is capable of https. 482 * 483 * In order for a server to run https, you must call 484 * soup_server_set_ssl_cert_file(), or set the 485 * #SoupServer:tls-certificate property, to provide it with a 486 * certificate to use. 487 * 488 * If you are using the deprecated single-listener APIs, then a return 489 * value of %TRUE indicates that the #SoupServer serves https 490 * exclusively. If you are using soup_server_listen(), etc, then a 491 * %TRUE return value merely indicates that the server is 492 * <emphasis>able</emphasis> to do https, regardless of whether it 493 * actually currently is or not. Use soup_server_get_uris() to see if 494 * it currently has any https listeners. 495 * 496 * Returns: %TRUE if @server is configured to serve https. 497 */ 498 public bool isHttps() 499 { 500 return soup_server_is_https(soupServer) != 0; 501 } 502 503 /** 504 * This attempts to set up @server to listen for connections on 505 * @address. 506 * 507 * If @options includes %SOUP_SERVER_LISTEN_HTTPS, and @server has 508 * been configured for TLS, then @server will listen for https 509 * connections on this port. Otherwise it will listen for plain http. 510 * 511 * You may call this method (along with the other "listen" methods) 512 * any number of times on a server, if you want to listen on multiple 513 * ports, or set up both http and https service. 514 * 515 * After calling this method, @server will begin accepting and 516 * processing connections as soon as the appropriate #GMainContext is 517 * run. 518 * 519 * Note that #SoupServer never makes use of dual IPv4/IPv6 sockets; if 520 * @address is an IPv6 address, it will only accept IPv6 connections. 521 * You must configure IPv4 listening separately. 522 * 523 * Params: 524 * address = the address of the interface to listen on 525 * options = listening options for this server 526 * 527 * Returns: %TRUE on success, %FALSE if @address could not be 528 * bound or any other error occurred (in which case @error will be 529 * set). 530 * 531 * Since: 2.48 532 * 533 * Throws: GException on failure. 534 */ 535 public bool listen(SocketAddress address, SoupServerListenOptions options) 536 { 537 GError* err = null; 538 539 auto __p = soup_server_listen(soupServer, (address is null) ? null : address.getSocketAddressStruct(), options, &err) != 0; 540 541 if (err !is null) 542 { 543 throw new GException( new ErrorG(err) ); 544 } 545 546 return __p; 547 } 548 549 /** 550 * This attempts to set up @server to listen for connections on all 551 * interfaces on the system. (That is, it listens on the addresses 552 * <literal>0.0.0.0</literal> and/or <literal>::</literal>, depending 553 * on whether @options includes %SOUP_SERVER_LISTEN_IPV4_ONLY, 554 * %SOUP_SERVER_LISTEN_IPV6_ONLY, or neither.) If @port is specified, 555 * @server will listen on that port. If it is 0, @server will find an 556 * unused port to listen on. (In that case, you can use 557 * soup_server_get_uris() to find out what port it ended up choosing.) 558 * 559 * See soup_server_listen() for more details. 560 * 561 * Params: 562 * port = the port to listen on, or 0 563 * options = listening options for this server 564 * 565 * Returns: %TRUE on success, %FALSE if @port could not be bound 566 * or any other error occurred (in which case @error will be set). 567 * 568 * Since: 2.48 569 * 570 * Throws: GException on failure. 571 */ 572 public bool listenAll(uint port, SoupServerListenOptions options) 573 { 574 GError* err = null; 575 576 auto __p = soup_server_listen_all(soupServer, port, options, &err) != 0; 577 578 if (err !is null) 579 { 580 throw new GException( new ErrorG(err) ); 581 } 582 583 return __p; 584 } 585 586 /** 587 * This attempts to set up @server to listen for connections on 588 * @fd. 589 * 590 * See soup_server_listen() for more details. 591 * 592 * Note that @server will close @fd when you free it or call 593 * soup_server_disconnect(). 594 * 595 * Params: 596 * fd = the file descriptor of a listening socket 597 * options = listening options for this server 598 * 599 * Returns: %TRUE on success, %FALSE if an error occurred (in 600 * which case @error will be set). 601 * 602 * Since: 2.48 603 * 604 * Throws: GException on failure. 605 */ 606 public bool listenFd(int fd, SoupServerListenOptions options) 607 { 608 GError* err = null; 609 610 auto __p = soup_server_listen_fd(soupServer, fd, options, &err) != 0; 611 612 if (err !is null) 613 { 614 throw new GException( new ErrorG(err) ); 615 } 616 617 return __p; 618 } 619 620 /** 621 * This attempts to set up @server to listen for connections on 622 * "localhost" (that is, <literal>127.0.0.1</literal> and/or 623 * <literal>::1</literal>, depending on whether @options includes 624 * %SOUP_SERVER_LISTEN_IPV4_ONLY, %SOUP_SERVER_LISTEN_IPV6_ONLY, or 625 * neither). If @port is specified, @server will listen on that port. 626 * If it is 0, @server will find an unused port to listen on. (In that 627 * case, you can use soup_server_get_uris() to find out what port it 628 * ended up choosing.) 629 * 630 * See soup_server_listen() for more details. 631 * 632 * Params: 633 * port = the port to listen on, or 0 634 * options = listening options for this server 635 * 636 * Returns: %TRUE on success, %FALSE if @port could not be bound 637 * or any other error occurred (in which case @error will be set). 638 * 639 * Since: 2.48 640 * 641 * Throws: GException on failure. 642 */ 643 public bool listenLocal(uint port, SoupServerListenOptions options) 644 { 645 GError* err = null; 646 647 auto __p = soup_server_listen_local(soupServer, port, options, &err) != 0; 648 649 if (err !is null) 650 { 651 throw new GException( new ErrorG(err) ); 652 } 653 654 return __p; 655 } 656 657 /** 658 * This attempts to set up @server to listen for connections on 659 * @socket. 660 * 661 * See soup_server_listen() for more details. 662 * 663 * Params: 664 * socket = a listening #GSocket 665 * options = listening options for this server 666 * 667 * Returns: %TRUE on success, %FALSE if an error occurred (in 668 * which case @error will be set). 669 * 670 * Since: 2.48 671 * 672 * Throws: GException on failure. 673 */ 674 public bool listenSocket(GIOSocket socket, SoupServerListenOptions options) 675 { 676 GError* err = null; 677 678 auto __p = soup_server_listen_socket(soupServer, (socket is null) ? null : socket.getSocketStruct(), options, &err) != 0; 679 680 if (err !is null) 681 { 682 throw new GException( new ErrorG(err) ); 683 } 684 685 return __p; 686 } 687 688 /** 689 * Pauses I/O on @msg. This can be used when you need to return from 690 * the server handler without having the full response ready yet. Use 691 * soup_server_unpause_message() to resume I/O. 692 * 693 * This must only be called on #SoupMessages which were created by the 694 * #SoupServer and are currently doing I/O, such as those passed into a 695 * #SoupServerCallback or emitted in a #SoupServer::request-read signal. 696 * 697 * Params: 698 * msg = a #SoupMessage associated with @server. 699 */ 700 public void pauseMessage(Message msg) 701 { 702 soup_server_pause_message(soupServer, (msg is null) ? null : msg.getMessageStruct()); 703 } 704 705 /** 706 * Stops processing for @server, if you are using the old API. Call 707 * this to clean up after soup_server_run_async(), or to terminate a 708 * call to soup_server_run(). 709 * 710 * Note that messages currently in progress will continue to be 711 * handled, if the main loop associated with the server is resumed or 712 * kept running. 713 * 714 * @server is still in a working state after this call; you can start 715 * and stop a server as many times as you want. 716 * 717 * Deprecated: When using soup_server_listen(), etc, the server will 718 * always listen for connections, and will process them whenever the 719 * thread-default #GMainContext is running. 720 */ 721 public void quit() 722 { 723 soup_server_quit(soupServer); 724 } 725 726 /** 727 * Removes @auth_domain from @server. 728 * 729 * Params: 730 * authDomain = a #SoupAuthDomain 731 */ 732 public void removeAuthDomain(AuthDomain authDomain) 733 { 734 soup_server_remove_auth_domain(soupServer, (authDomain is null) ? null : authDomain.getAuthDomainStruct()); 735 } 736 737 /** 738 * Removes all handlers (early and normal) registered at @path. 739 * 740 * Params: 741 * path = the toplevel path for the handler 742 */ 743 public void removeHandler(string path) 744 { 745 soup_server_remove_handler(soupServer, Str.toStringz(path)); 746 } 747 748 /** 749 * Removes support for WebSocket extension of type @extension_type (or any subclass of 750 * @extension_type) from @server. You can also remove extensions enabled by default 751 * from the server at construct time by using the %SOUP_SERVER_REMOVE_WEBSOCKET_EXTENSION 752 * property. 753 * 754 * Params: 755 * extensionType = a #GType 756 * 757 * Since: 2.68 758 */ 759 public void removeWebsocketExtension(GType extensionType) 760 { 761 soup_server_remove_websocket_extension(soupServer, extensionType); 762 } 763 764 /** 765 * Starts @server, if you are using the old API, causing it to listen 766 * for and process incoming connections. Unlike 767 * soup_server_run_async(), this creates a #GMainLoop and runs it, and 768 * it will not return until someone calls soup_server_quit() to stop 769 * the server. 770 * 771 * Deprecated: When using soup_server_listen(), etc, the server will 772 * always listen for connections, and will process them whenever the 773 * thread-default #GMainContext is running. 774 */ 775 public void run() 776 { 777 soup_server_run(soupServer); 778 } 779 780 /** 781 * Starts @server, if you are using the old API, causing it to listen 782 * for and process incoming connections. 783 * 784 * The server runs in @server's #GMainContext. It will not actually 785 * perform any processing unless the appropriate main loop is running. 786 * In the simple case where you did not set the server's 787 * %SOUP_SERVER_ASYNC_CONTEXT property, this means the server will run 788 * whenever the glib main loop is running. 789 * 790 * Deprecated: When using soup_server_listen(), etc, the server will 791 * always listen for connections, and will process them whenever the 792 * thread-default #GMainContext is running. 793 */ 794 public void runAsync() 795 { 796 soup_server_run_async(soupServer); 797 } 798 799 /** 800 * Sets @server up to do https, using the SSL/TLS certificate 801 * specified by @ssl_cert_file and @ssl_key_file (which may point to 802 * the same file). 803 * 804 * Alternatively, you can set the #SoupServer:tls-certificate property 805 * at construction time, if you already have a #GTlsCertificate. 806 * 807 * Params: 808 * sslCertFile = path to a file containing a PEM-encoded SSL/TLS 809 * certificate. 810 * sslKeyFile = path to a file containing a PEM-encoded private key. 811 * 812 * Returns: success or failure. 813 * 814 * Since: 2.48 815 * 816 * Throws: GException on failure. 817 */ 818 public bool setSslCertFile(string sslCertFile, string sslKeyFile) 819 { 820 GError* err = null; 821 822 auto __p = soup_server_set_ssl_cert_file(soupServer, Str.toStringz(sslCertFile), Str.toStringz(sslKeyFile), &err) != 0; 823 824 if (err !is null) 825 { 826 throw new GException( new ErrorG(err) ); 827 } 828 829 return __p; 830 } 831 832 /** 833 * Resumes I/O on @msg. Use this to resume after calling 834 * soup_server_pause_message(), or after adding a new chunk to a 835 * chunked response. 836 * 837 * I/O won't actually resume until you return to the main loop. 838 * 839 * This must only be called on #SoupMessages which were created by the 840 * #SoupServer and are currently doing I/O, such as those passed into a 841 * #SoupServerCallback or emitted in a #SoupServer::request-read signal. 842 * 843 * Params: 844 * msg = a #SoupMessage associated with @server. 845 */ 846 public void unpauseMessage(Message msg) 847 { 848 soup_server_unpause_message(soupServer, (msg is null) ? null : msg.getMessageStruct()); 849 } 850 851 /** 852 * Emitted when processing has failed for a message; this 853 * could mean either that it could not be read (if 854 * #SoupServer::request_read has not been emitted for it yet), 855 * or that the response could not be written back (if 856 * #SoupServer::request_read has been emitted but 857 * #SoupServer::request_finished has not been). 858 * 859 * @message is in an undefined state when this signal is 860 * emitted; the signal exists primarily to allow the server to 861 * free any state that it may have allocated in 862 * #SoupServer::request_started. 863 * 864 * Params: 865 * message = the message 866 * client = the client context 867 */ 868 gulong addOnRequestAborted(void delegate(Message, ClientContext, Server) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 869 { 870 return Signals.connect(this, "request-aborted", dlg, connectFlags ^ ConnectFlags.SWAPPED); 871 } 872 873 /** 874 * Emitted when the server has finished writing a response to 875 * a request. 876 * 877 * Params: 878 * message = the message 879 * client = the client context 880 */ 881 gulong addOnRequestFinished(void delegate(Message, ClientContext, Server) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 882 { 883 return Signals.connect(this, "request-finished", dlg, connectFlags ^ ConnectFlags.SWAPPED); 884 } 885 886 /** 887 * Emitted when the server has successfully read a request. 888 * @message will have all of its request-side information 889 * filled in, and if the message was authenticated, @client 890 * will have information about that. This signal is emitted 891 * before any (non-early) handlers are called for the message, 892 * and if it sets the message's #status_code, then normal 893 * handler processing will be skipped. 894 * 895 * Params: 896 * message = the message 897 * client = the client context 898 */ 899 gulong addOnRequestRead(void delegate(Message, ClientContext, Server) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 900 { 901 return Signals.connect(this, "request-read", dlg, connectFlags ^ ConnectFlags.SWAPPED); 902 } 903 904 /** 905 * Emitted when the server has started reading a new request. 906 * @message will be completely blank; not even the 907 * Request-Line will have been read yet. About the only thing 908 * you can usefully do with it is connect to its signals. 909 * 910 * If the request is read successfully, this will eventually 911 * be followed by a #SoupServer::request_read signal. If a 912 * response is then sent, the request processing will end with 913 * a #SoupServer::request_finished signal. If a network error 914 * occurs, the processing will instead end with 915 * #SoupServer::request_aborted. 916 * 917 * Params: 918 * message = the new message 919 * client = the client context 920 */ 921 gulong addOnRequestStarted(void delegate(Message, ClientContext, Server) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 922 { 923 return Signals.connect(this, "request-started", dlg, connectFlags ^ ConnectFlags.SWAPPED); 924 } 925 }