1 module soup.Session; 2 3 private import gio.AsyncResultIF; 4 private import gio.Cancellable; 5 private import gio.IOStream; 6 private import gio.InputStream; 7 private import glib.ConstructionException; 8 private import glib.ErrorG; 9 private import glib.GException; 10 private import glib.ListSG; 11 private import glib.MainContext; 12 private import glib.Str; 13 private import gobject.ObjectG; 14 private import gobject.Signals; 15 private import soup.Auth; 16 private import soup.Message; 17 private import soup.Request; 18 private import soup.RequestHTTP; 19 private import soup.SessionFeatureIF; 20 private import soup.Socket; 21 private import soup.URI; 22 private import soup.WebsocketConnection; 23 private import soup.c.functions; 24 public import soup.c.types; 25 private import std.algorithm; 26 27 28 /** 29 * #SoupSession is the object that controls client-side HTTP. A 30 * #SoupSession encapsulates all of the state that libsoup is keeping 31 * on behalf of your program; cached HTTP connections, authentication 32 * information, etc. It also keeps track of various global options 33 * and features that you are using. 34 * 35 * Most applications will only need a single #SoupSession; the primary 36 * reason you might need multiple sessions is if you need to have 37 * multiple independent authentication contexts. (Eg, you are 38 * connecting to a server and authenticating as two different users at 39 * different times; the easiest way to ensure that each #SoupMessage 40 * is sent with the authentication information you intended is to use 41 * one session for the first user, and a second session for the other 42 * user.) 43 * 44 * In the past, #SoupSession was an abstract class, and users needed 45 * to choose between #SoupSessionAsync (which always uses 46 * #GMainLoop<!-- -->-based I/O), or #SoupSessionSync (which always uses 47 * blocking I/O and can be used from multiple threads simultaneously). 48 * This is no longer necessary; you can (and should) use a plain 49 * #SoupSession, which supports both synchronous and asynchronous use. 50 * (When using a plain #SoupSession, soup_session_queue_message() 51 * behaves like it traditionally did on a #SoupSessionAsync, and 52 * soup_session_send_message() behaves like it traditionally did on a 53 * #SoupSessionSync.) 54 * 55 * Additional #SoupSession functionality is provided by 56 * #SoupSessionFeature objects, which can be added to a session with 57 * soup_session_add_feature() or soup_session_add_feature_by_type() 58 * (or at construct time with the %SOUP_SESSION_ADD_FEATURE_BY_TYPE 59 * pseudo-property). For example, #SoupLogger provides support for 60 * logging HTTP traffic, #SoupContentDecoder provides support for 61 * compressed response handling, and #SoupContentSniffer provides 62 * support for HTML5-style response body content sniffing. 63 * Additionally, subtypes of #SoupAuth and #SoupRequest can be added 64 * as features, to add support for additional authentication and URI 65 * types. 66 * 67 * All #SoupSessions are created with a #SoupAuthManager, and support 68 * for %SOUP_TYPE_AUTH_BASIC and %SOUP_TYPE_AUTH_DIGEST. For 69 * #SoupRequest types, #SoupRequestHTTP, #SoupRequestFile, and 70 * #SoupRequestData are supported. Additionally, sessions using the 71 * plain #SoupSession class (rather than one of its deprecated 72 * subtypes) have a #SoupContentDecoder by default. 73 */ 74 public class Session : ObjectG 75 { 76 /** the main Gtk struct */ 77 protected SoupSession* soupSession; 78 79 /** Get the main Gtk struct */ 80 public SoupSession* getSessionStruct(bool transferOwnership = false) 81 { 82 if (transferOwnership) 83 ownedRef = false; 84 return soupSession; 85 } 86 87 /** the main Gtk struct as a void* */ 88 protected override void* getStruct() 89 { 90 return cast(void*)soupSession; 91 } 92 93 /** 94 * Sets our main struct and passes it to the parent class. 95 */ 96 public this (SoupSession* soupSession, bool ownedRef = false) 97 { 98 this.soupSession = soupSession; 99 super(cast(GObject*)soupSession, ownedRef); 100 } 101 102 103 /** */ 104 public static GType getType() 105 { 106 return soup_session_get_type(); 107 } 108 109 /** 110 * Creates a #SoupSession with the default options. 111 * 112 * Returns: the new session. 113 * 114 * Since: 2.42 115 * 116 * Throws: ConstructionException GTK+ fails to create the object. 117 */ 118 public this() 119 { 120 auto __p = soup_session_new(); 121 122 if(__p is null) 123 { 124 throw new ConstructionException("null returned by new"); 125 } 126 127 this(cast(SoupSession*) __p, true); 128 } 129 130 /** 131 * Cancels all pending requests in @session and closes all idle 132 * persistent connections. 133 * 134 * The message cancellation has the same semantics as with 135 * soup_session_cancel_message(); asynchronous requests on a 136 * #SoupSessionAsync will have their callback called before 137 * soup_session_abort() returns. Requests on a plain #SoupSession will 138 * not. 139 */ 140 public void abort() 141 { 142 soup_session_abort(soupSession); 143 } 144 145 /** 146 * Adds @feature's functionality to @session. You can also add a 147 * feature to the session at construct time by using the 148 * %SOUP_SESSION_ADD_FEATURE property. 149 * 150 * See the main #SoupSession documentation for information on what 151 * features are present in sessions by default. 152 * 153 * Params: 154 * feature = an object that implements #SoupSessionFeature 155 * 156 * Since: 2.24 157 */ 158 public void addFeature(SessionFeatureIF feature) 159 { 160 soup_session_add_feature(soupSession, (feature is null) ? null : feature.getSessionFeatureStruct()); 161 } 162 163 /** 164 * If @feature_type is the type of a class that implements 165 * #SoupSessionFeature, this creates a new feature of that type and 166 * adds it to @session as with soup_session_add_feature(). You can use 167 * this when you don't need to customize the new feature in any way. 168 * 169 * If @feature_type is not a #SoupSessionFeature type, this gives each 170 * existing feature on @session the chance to accept @feature_type as 171 * a "subfeature". This can be used to add new #SoupAuth or 172 * #SoupRequest types, for instance. 173 * 174 * You can also add a feature to the session at construct time by 175 * using the %SOUP_SESSION_ADD_FEATURE_BY_TYPE property. 176 * 177 * See the main #SoupSession documentation for information on what 178 * features are present in sessions by default. 179 * 180 * Params: 181 * featureType = a #GType 182 * 183 * Since: 2.24 184 */ 185 public void addFeatureByType(GType featureType) 186 { 187 soup_session_add_feature_by_type(soupSession, featureType); 188 } 189 190 /** 191 * Causes @session to immediately finish processing @msg (regardless 192 * of its current state) with a final status_code of @status_code. You 193 * may call this at any time after handing @msg off to @session; if 194 * @session has started sending the request but has not yet received 195 * the complete response, then it will close the request's connection. 196 * Note that with requests that have side effects (eg, 197 * <literal>POST</literal>, <literal>PUT</literal>, 198 * <literal>DELETE</literal>) it is possible that you might cancel the 199 * request after the server acts on it, but before it returns a 200 * response, leaving the remote resource in an unknown state. 201 * 202 * If the message is cancelled while its response body is being read, 203 * then the response body in @msg will be left partially-filled-in. 204 * The response headers, on the other hand, will always be either 205 * empty or complete. 206 * 207 * Beware that with the deprecated #SoupSessionAsync, messages queued 208 * with soup_session_queue_message() will have their callbacks invoked 209 * before soup_session_cancel_message() returns. The plain 210 * #SoupSession does not have this behavior; cancelling an 211 * asynchronous message will merely queue its callback to be run after 212 * returning to the main loop. 213 * 214 * Params: 215 * msg = the message to cancel 216 * statusCode = status code to set on @msg (generally 217 * %SOUP_STATUS_CANCELLED) 218 */ 219 public void cancelMessage(Message msg, uint statusCode) 220 { 221 soup_session_cancel_message(soupSession, (msg is null) ? null : msg.getMessageStruct(), statusCode); 222 } 223 224 /** 225 * Start a connection to @uri. The operation can be monitored by providing a @progress_callback 226 * and finishes when the connection is done or an error ocurred. 227 * 228 * Call soup_session_connect_finish() to get the #GIOStream to communicate with the server. 229 * 230 * Params: 231 * uri = a #SoupURI to connect to 232 * cancellable = a #GCancellable 233 * progressCallback = a #SoupSessionConnectProgressCallback which 234 * will be called for every network event that occurs during the connection. 235 * callback = the callback to invoke when the operation finishes 236 * userData = data for @progress_callback and @callback 237 * 238 * Since: 2.62 239 */ 240 public void connectAsync(URI uri, Cancellable cancellable, SoupSessionConnectProgressCallback progressCallback, GAsyncReadyCallback callback, void* userData) 241 { 242 soup_session_connect_async(soupSession, (uri is null) ? null : uri.getURIStruct(), (cancellable is null) ? null : cancellable.getCancellableStruct(), progressCallback, callback, userData); 243 } 244 245 /** 246 * Gets the #GIOStream created for the connection to communicate with the server. 247 * 248 * Params: 249 * result = the #GAsyncResult passed to your callback 250 * 251 * Returns: a new #GIOStream, or %NULL on error. 252 * 253 * Since: 2.62 254 * 255 * Throws: GException on failure. 256 */ 257 public IOStream connectFinish(AsyncResultIF result) 258 { 259 GError* err = null; 260 261 auto __p = soup_session_connect_finish(soupSession, (result is null) ? null : result.getAsyncResultStruct(), &err); 262 263 if (err !is null) 264 { 265 throw new GException( new ErrorG(err) ); 266 } 267 268 if(__p is null) 269 { 270 return null; 271 } 272 273 return ObjectG.getDObject!(IOStream)(cast(GIOStream*) __p, true); 274 } 275 276 /** 277 * Gets @session's #SoupSession:async-context. This does not add a ref 278 * to the context, so you will need to ref it yourself if you want it 279 * to outlive its session. 280 * 281 * For a modern #SoupSession, this will always just return the 282 * thread-default #GMainContext, and so is not especially useful. 283 * 284 * Returns: @session's #GMainContext, 285 * which may be %NULL 286 */ 287 public MainContext getAsyncContext() 288 { 289 auto __p = soup_session_get_async_context(soupSession); 290 291 if(__p is null) 292 { 293 return null; 294 } 295 296 return new MainContext(cast(GMainContext*) __p); 297 } 298 299 /** 300 * Gets the first feature in @session of type @feature_type. For 301 * features where there may be more than one feature of a given type, 302 * use soup_session_get_features(). 303 * 304 * Params: 305 * featureType = the #GType of the feature to get 306 * 307 * Returns: a #SoupSessionFeature, or 308 * %NULL. The feature is owned by @session. 309 * 310 * Since: 2.26 311 */ 312 public SessionFeatureIF getFeature(GType featureType) 313 { 314 auto __p = soup_session_get_feature(soupSession, featureType); 315 316 if(__p is null) 317 { 318 return null; 319 } 320 321 return ObjectG.getDObject!(SessionFeatureIF)(cast(SoupSessionFeature*) __p); 322 } 323 324 /** 325 * Gets the first feature in @session of type @feature_type, provided 326 * that it is not disabled for @msg. As with 327 * soup_session_get_feature(), this should only be used for features 328 * where @feature_type is only expected to match a single feature. In 329 * particular, if there are two matching features, and the first is 330 * disabled on @msg, and the second is not, then this will return 331 * %NULL, not the second feature. 332 * 333 * Params: 334 * featureType = the #GType of the feature to get 335 * msg = a #SoupMessage 336 * 337 * Returns: a #SoupSessionFeature, or %NULL. The 338 * feature is owned by @session. 339 * 340 * Since: 2.28 341 */ 342 public SessionFeatureIF getFeatureForMessage(GType featureType, Message msg) 343 { 344 auto __p = soup_session_get_feature_for_message(soupSession, featureType, (msg is null) ? null : msg.getMessageStruct()); 345 346 if(__p is null) 347 { 348 return null; 349 } 350 351 return ObjectG.getDObject!(SessionFeatureIF)(cast(SoupSessionFeature*) __p); 352 } 353 354 /** 355 * Generates a list of @session's features of type @feature_type. (If 356 * you want to see all features, you can pass %SOUP_TYPE_SESSION_FEATURE 357 * for @feature_type.) 358 * 359 * Params: 360 * featureType = the #GType of the class of features to get 361 * 362 * Returns: a list of features. You must free the list, but not its contents 363 * 364 * Since: 2.26 365 */ 366 public ListSG getFeatures(GType featureType) 367 { 368 auto __p = soup_session_get_features(soupSession, featureType); 369 370 if(__p is null) 371 { 372 return null; 373 } 374 375 return new ListSG(cast(GSList*) __p); 376 } 377 378 /** 379 * Tests if @session has at a feature of type @feature_type (which can 380 * be the type of either a #SoupSessionFeature, or else a subtype of 381 * some class managed by another feature, such as #SoupAuth or 382 * #SoupRequest). 383 * 384 * Params: 385 * featureType = the #GType of the class of features to check for 386 * 387 * Returns: %TRUE or %FALSE 388 * 389 * Since: 2.42 390 */ 391 public bool hasFeature(GType featureType) 392 { 393 return soup_session_has_feature(soupSession, featureType) != 0; 394 } 395 396 /** 397 * Pauses HTTP I/O on @msg. Call soup_session_unpause_message() to 398 * resume I/O. 399 * 400 * This may only be called for asynchronous messages (those sent on a 401 * #SoupSessionAsync or using soup_session_queue_message()). 402 * 403 * Params: 404 * msg = a #SoupMessage currently running on @session 405 */ 406 public void pauseMessage(Message msg) 407 { 408 soup_session_pause_message(soupSession, (msg is null) ? null : msg.getMessageStruct()); 409 } 410 411 /** 412 * Tells @session that an URI from the given @hostname may be requested 413 * shortly, and so the session can try to prepare by resolving the 414 * domain name in advance, in order to work more quickly once the URI 415 * is actually requested. 416 * 417 * If @cancellable is non-%NULL, it can be used to cancel the 418 * resolution. @callback will still be invoked in this case, with a 419 * status of %SOUP_STATUS_CANCELLED. 420 * 421 * Params: 422 * hostname = a hostname to be resolved 423 * cancellable = a #GCancellable object, or %NULL 424 * callback = callback to call with the 425 * result, or %NULL 426 * userData = data for @callback 427 * 428 * Since: 2.38 429 */ 430 public void prefetchDns(string hostname, Cancellable cancellable, SoupAddressCallback callback, void* userData) 431 { 432 soup_session_prefetch_dns(soupSession, Str.toStringz(hostname), (cancellable is null) ? null : cancellable.getCancellableStruct(), callback, userData); 433 } 434 435 /** 436 * Tells @session that @uri may be requested shortly, and so the 437 * session can try to prepare (resolving the domain name, obtaining 438 * proxy address, etc.) in order to work more quickly once the URI is 439 * actually requested. 440 * 441 * Deprecated: use soup_session_prefetch_dns() instead 442 * 443 * Params: 444 * uri = a #SoupURI which may be required 445 * 446 * Since: 2.30 447 */ 448 public void prepareForUri(URI uri) 449 { 450 soup_session_prepare_for_uri(soupSession, (uri is null) ? null : uri.getURIStruct()); 451 } 452 453 /** 454 * Queues the message @msg for asynchronously sending the request and 455 * receiving a response in the current thread-default #GMainContext. 456 * If @msg has been processed before, any resources related to the 457 * time it was last sent are freed. 458 * 459 * Upon message completion, the callback specified in @callback will 460 * be invoked. If after returning from this callback the message has not 461 * been requeued, @msg will be unreffed. 462 * 463 * (The behavior above applies to a plain #SoupSession; if you are 464 * using #SoupSessionAsync or #SoupSessionSync, then the #GMainContext 465 * that is used depends on the settings of #SoupSession:async-context 466 * and #SoupSession:use-thread-context, and for #SoupSessionSync, the 467 * message will actually be sent and processed in another thread, with 468 * only the final callback occurring in the indicated #GMainContext.) 469 * 470 * Contrast this method with soup_session_send_async(), which also 471 * asynchronously sends a message, but returns before reading the 472 * response body, and allows you to read the response via a 473 * #GInputStream. 474 * 475 * Params: 476 * msg = the message to queue 477 * callback = a #SoupSessionCallback which will 478 * be called after the message completes or when an unrecoverable error occurs. 479 * userData = a pointer passed to @callback. 480 */ 481 public void queueMessage(Message msg, SoupSessionCallback callback, void* userData) 482 { 483 soup_session_queue_message(soupSession, (msg is null) ? null : msg.getMessageStruct(), callback, userData); 484 } 485 486 /** 487 * Updates @msg's URI according to its status code and "Location" 488 * header, and requeues it on @session. Use this when you have set 489 * %SOUP_MESSAGE_NO_REDIRECT on a message, but have decided to allow a 490 * particular redirection to occur, or if you want to allow a 491 * redirection that #SoupSession will not perform automatically (eg, 492 * redirecting a non-safe method such as DELETE). 493 * 494 * If @msg's status code indicates that it should be retried as a GET 495 * request, then @msg will be modified accordingly. 496 * 497 * If @msg has already been redirected too many times, this will 498 * cause it to fail with %SOUP_STATUS_TOO_MANY_REDIRECTS. 499 * 500 * Params: 501 * msg = a #SoupMessage that has received a 3xx response 502 * 503 * Returns: %TRUE if a redirection was applied, %FALSE if not 504 * (eg, because there was no Location header, or it could not be 505 * parsed). 506 * 507 * Since: 2.38 508 */ 509 public bool redirectMessage(Message msg) 510 { 511 return soup_session_redirect_message(soupSession, (msg is null) ? null : msg.getMessageStruct()) != 0; 512 } 513 514 /** 515 * Removes @feature's functionality from @session. 516 * 517 * Params: 518 * feature = a feature that has previously been added to @session 519 * 520 * Since: 2.24 521 */ 522 public void removeFeature(SessionFeatureIF feature) 523 { 524 soup_session_remove_feature(soupSession, (feature is null) ? null : feature.getSessionFeatureStruct()); 525 } 526 527 /** 528 * Removes all features of type @feature_type (or any subclass of 529 * @feature_type) from @session. You can also remove standard features 530 * from the session at construct time by using the 531 * %SOUP_SESSION_REMOVE_FEATURE_BY_TYPE property. 532 * 533 * Params: 534 * featureType = a #GType 535 * 536 * Since: 2.24 537 */ 538 public void removeFeatureByType(GType featureType) 539 { 540 soup_session_remove_feature_by_type(soupSession, featureType); 541 } 542 543 /** 544 * Creates a #SoupRequest for retrieving @uri_string. 545 * 546 * Params: 547 * uriString = a URI, in string form 548 * 549 * Returns: a new #SoupRequest, or 550 * %NULL on error. 551 * 552 * Since: 2.42 553 * 554 * Throws: GException on failure. 555 */ 556 public Request request(string uriString) 557 { 558 GError* err = null; 559 560 auto __p = soup_session_request(soupSession, Str.toStringz(uriString), &err); 561 562 if (err !is null) 563 { 564 throw new GException( new ErrorG(err) ); 565 } 566 567 if(__p is null) 568 { 569 return null; 570 } 571 572 return ObjectG.getDObject!(Request)(cast(SoupRequest*) __p, true); 573 } 574 575 /** 576 * Creates a #SoupRequest for retrieving @uri_string, which must be an 577 * "http" or "https" URI (or another protocol listed in @session's 578 * #SoupSession:http-aliases or #SoupSession:https-aliases). 579 * 580 * Params: 581 * method = an HTTP method 582 * uriString = a URI, in string form 583 * 584 * Returns: a new #SoupRequestHTTP, or 585 * %NULL on error. 586 * 587 * Since: 2.42 588 * 589 * Throws: GException on failure. 590 */ 591 public RequestHTTP requestHttp(string method, string uriString) 592 { 593 GError* err = null; 594 595 auto __p = soup_session_request_http(soupSession, Str.toStringz(method), Str.toStringz(uriString), &err); 596 597 if (err !is null) 598 { 599 throw new GException( new ErrorG(err) ); 600 } 601 602 if(__p is null) 603 { 604 return null; 605 } 606 607 return ObjectG.getDObject!(RequestHTTP)(cast(SoupRequestHTTP*) __p, true); 608 } 609 610 /** 611 * Creates a #SoupRequest for retrieving @uri, which must be an 612 * "http" or "https" URI (or another protocol listed in @session's 613 * #SoupSession:http-aliases or #SoupSession:https-aliases). 614 * 615 * Params: 616 * method = an HTTP method 617 * uri = a #SoupURI representing the URI to retrieve 618 * 619 * Returns: a new #SoupRequestHTTP, or 620 * %NULL on error. 621 * 622 * Since: 2.42 623 * 624 * Throws: GException on failure. 625 */ 626 public RequestHTTP requestHttpUri(string method, URI uri) 627 { 628 GError* err = null; 629 630 auto __p = soup_session_request_http_uri(soupSession, Str.toStringz(method), (uri is null) ? null : uri.getURIStruct(), &err); 631 632 if (err !is null) 633 { 634 throw new GException( new ErrorG(err) ); 635 } 636 637 if(__p is null) 638 { 639 return null; 640 } 641 642 return ObjectG.getDObject!(RequestHTTP)(cast(SoupRequestHTTP*) __p, true); 643 } 644 645 /** 646 * Creates a #SoupRequest for retrieving @uri. 647 * 648 * Params: 649 * uri = a #SoupURI representing the URI to retrieve 650 * 651 * Returns: a new #SoupRequest, or 652 * %NULL on error. 653 * 654 * Since: 2.42 655 * 656 * Throws: GException on failure. 657 */ 658 public Request requestUri(URI uri) 659 { 660 GError* err = null; 661 662 auto __p = soup_session_request_uri(soupSession, (uri is null) ? null : uri.getURIStruct(), &err); 663 664 if (err !is null) 665 { 666 throw new GException( new ErrorG(err) ); 667 } 668 669 if(__p is null) 670 { 671 return null; 672 } 673 674 return ObjectG.getDObject!(Request)(cast(SoupRequest*) __p, true); 675 } 676 677 /** 678 * This causes @msg to be placed back on the queue to be attempted 679 * again. 680 * 681 * Params: 682 * msg = the message to requeue 683 */ 684 public void requeueMessage(Message msg) 685 { 686 soup_session_requeue_message(soupSession, (msg is null) ? null : msg.getMessageStruct()); 687 } 688 689 /** 690 * Synchronously sends @msg and waits for the beginning of a response. 691 * On success, a #GInputStream will be returned which you can use to 692 * read the response body. ("Success" here means only that an HTTP 693 * response was received and understood; it does not necessarily mean 694 * that a 2xx class status code was received.) 695 * 696 * If non-%NULL, @cancellable can be used to cancel the request; 697 * soup_session_send() will return a %G_IO_ERROR_CANCELLED error. Note 698 * that with requests that have side effects (eg, 699 * <literal>POST</literal>, <literal>PUT</literal>, 700 * <literal>DELETE</literal>) it is possible that you might cancel the 701 * request after the server acts on it, but before it returns a 702 * response, leaving the remote resource in an unknown state. 703 * 704 * If @msg is requeued due to a redirect or authentication, the 705 * initial (3xx/401/407) response body will be suppressed, and 706 * soup_session_send() will only return once a final response has been 707 * received. 708 * 709 * Contrast this method with soup_session_send_message(), which also 710 * synchronously sends a #SoupMessage, but doesn't return until the 711 * response has been completely read. 712 * 713 * (Note that this method cannot be called on the deprecated 714 * #SoupSessionAsync subclass.) 715 * 716 * Params: 717 * msg = a #SoupMessage 718 * cancellable = a #GCancellable 719 * 720 * Returns: a #GInputStream for reading the 721 * response body, or %NULL on error. 722 * 723 * Since: 2.42 724 * 725 * Throws: GException on failure. 726 */ 727 public InputStream send(Message msg, Cancellable cancellable) 728 { 729 GError* err = null; 730 731 auto __p = soup_session_send(soupSession, (msg is null) ? null : msg.getMessageStruct(), (cancellable is null) ? null : cancellable.getCancellableStruct(), &err); 732 733 if (err !is null) 734 { 735 throw new GException( new ErrorG(err) ); 736 } 737 738 if(__p is null) 739 { 740 return null; 741 } 742 743 return ObjectG.getDObject!(InputStream)(cast(GInputStream*) __p, true); 744 } 745 746 /** 747 * Asynchronously sends @msg and waits for the beginning of a 748 * response. When @callback is called, then either @msg has been sent, 749 * and its response headers received, or else an error has occurred. 750 * Call soup_session_send_finish() to get a #GInputStream for reading 751 * the response body. 752 * 753 * See soup_session_send() for more details on the general semantics. 754 * 755 * Contrast this method with soup_session_queue_message(), which also 756 * asynchronously sends a #SoupMessage, but doesn't invoke its 757 * callback until the response has been completely read. 758 * 759 * (Note that this method cannot be called on the deprecated 760 * #SoupSessionSync subclass, and can only be called on 761 * #SoupSessionAsync if you have set the 762 * #SoupSession:use-thread-context property.) 763 * 764 * Params: 765 * msg = a #SoupMessage 766 * cancellable = a #GCancellable 767 * callback = the callback to invoke 768 * userData = data for @callback 769 * 770 * Since: 2.42 771 */ 772 public void sendAsync(Message msg, Cancellable cancellable, GAsyncReadyCallback callback, void* userData) 773 { 774 soup_session_send_async(soupSession, (msg is null) ? null : msg.getMessageStruct(), (cancellable is null) ? null : cancellable.getCancellableStruct(), callback, userData); 775 } 776 777 /** 778 * Gets the response to a soup_session_send_async() call and (if 779 * successful), returns a #GInputStream that can be used to read the 780 * response body. 781 * 782 * Params: 783 * result = the #GAsyncResult passed to your callback 784 * 785 * Returns: a #GInputStream for reading the 786 * response body, or %NULL on error. 787 * 788 * Since: 2.42 789 * 790 * Throws: GException on failure. 791 */ 792 public InputStream sendFinish(AsyncResultIF result) 793 { 794 GError* err = null; 795 796 auto __p = soup_session_send_finish(soupSession, (result is null) ? null : result.getAsyncResultStruct(), &err); 797 798 if (err !is null) 799 { 800 throw new GException( new ErrorG(err) ); 801 } 802 803 if(__p is null) 804 { 805 return null; 806 } 807 808 return ObjectG.getDObject!(InputStream)(cast(GInputStream*) __p, true); 809 } 810 811 /** 812 * Synchronously send @msg. This call will not return until the 813 * transfer is finished successfully or there is an unrecoverable 814 * error. 815 * 816 * Unlike with soup_session_queue_message(), @msg is not freed upon 817 * return. 818 * 819 * (Note that if you call this method on a #SoupSessionAsync, it will 820 * still use asynchronous I/O internally, running the glib main loop 821 * to process the message, which may also cause other events to be 822 * processed.) 823 * 824 * Contrast this method with soup_session_send(), which also 825 * synchronously sends a message, but returns before reading the 826 * response body, and allows you to read the response via a 827 * #GInputStream. 828 * 829 * Params: 830 * msg = the message to send 831 * 832 * Returns: the HTTP status code of the response 833 */ 834 public uint sendMessage(Message msg) 835 { 836 return soup_session_send_message(soupSession, (msg is null) ? null : msg.getMessageStruct()); 837 } 838 839 /** 840 * "Steals" the HTTP connection associated with @msg from @session. 841 * This happens immediately, regardless of the current state of the 842 * connection, and @msg's callback will not be called. You can steal 843 * the connection from a #SoupMessage signal handler if you need to 844 * wait for part or all of the response to be received first. 845 * 846 * Calling this function may cause @msg to be freed if you are not 847 * holding any other reference to it. 848 * 849 * Params: 850 * msg = the message whose connection is to be stolen 851 * 852 * Returns: the #GIOStream formerly associated 853 * with @msg (or %NULL if @msg was no longer associated with a 854 * connection). No guarantees are made about what kind of #GIOStream 855 * is returned. 856 * 857 * Since: 2.50 858 */ 859 public IOStream stealConnection(Message msg) 860 { 861 auto __p = soup_session_steal_connection(soupSession, (msg is null) ? null : msg.getMessageStruct()); 862 863 if(__p is null) 864 { 865 return null; 866 } 867 868 return ObjectG.getDObject!(IOStream)(cast(GIOStream*) __p, true); 869 } 870 871 /** 872 * Resumes HTTP I/O on @msg. Use this to resume after calling 873 * soup_session_pause_message(). 874 * 875 * If @msg is being sent via blocking I/O, this will resume reading or 876 * writing immediately. If @msg is using non-blocking I/O, then 877 * reading or writing won't resume until you return to the main loop. 878 * 879 * This may only be called for asynchronous messages (those sent on a 880 * #SoupSessionAsync or using soup_session_queue_message()). 881 * 882 * Params: 883 * msg = a #SoupMessage currently running on @session 884 */ 885 public void unpauseMessage(Message msg) 886 { 887 soup_session_unpause_message(soupSession, (msg is null) ? null : msg.getMessageStruct()); 888 } 889 890 /** 891 * Asynchronously creates a #SoupWebsocketConnection to communicate 892 * with a remote server. 893 * 894 * All necessary WebSocket-related headers will be added to @msg, and 895 * it will then be sent and asynchronously processed normally 896 * (including handling of redirection and HTTP authentication). 897 * 898 * If the server returns "101 Switching Protocols", then @msg's status 899 * code and response headers will be updated, and then the WebSocket 900 * handshake will be completed. On success, 901 * soup_session_websocket_connect_finish() will return a new 902 * #SoupWebsocketConnection. On failure it will return a #GError. 903 * 904 * If the server returns a status other than "101 Switching 905 * Protocols", then @msg will contain the complete response headers 906 * and body from the server's response, and 907 * soup_session_websocket_connect_finish() will return 908 * %SOUP_WEBSOCKET_ERROR_NOT_WEBSOCKET. 909 * 910 * Params: 911 * msg = #SoupMessage indicating the WebSocket server to connect to 912 * origin = origin of the connection 913 * protocols = a 914 * %NULL-terminated array of protocols supported 915 * cancellable = a #GCancellable 916 * callback = the callback to invoke 917 * userData = data for @callback 918 * 919 * Since: 2.50 920 */ 921 public void websocketConnectAsync(Message msg, string origin, string[] protocols, Cancellable cancellable, GAsyncReadyCallback callback, void* userData) 922 { 923 soup_session_websocket_connect_async(soupSession, (msg is null) ? null : msg.getMessageStruct(), Str.toStringz(origin), Str.toStringzArray(protocols), (cancellable is null) ? null : cancellable.getCancellableStruct(), callback, userData); 924 } 925 926 /** 927 * Gets the #SoupWebsocketConnection response to a 928 * soup_session_websocket_connect_async() call and (if successful), 929 * returns a #SoupWebsocketConnection that can be used to communicate 930 * with the server. 931 * 932 * Params: 933 * result = the #GAsyncResult passed to your callback 934 * 935 * Returns: a new #SoupWebsocketConnection, or 936 * %NULL on error. 937 * 938 * Since: 2.50 939 * 940 * Throws: GException on failure. 941 */ 942 public WebsocketConnection websocketConnectFinish(AsyncResultIF result) 943 { 944 GError* err = null; 945 946 auto __p = soup_session_websocket_connect_finish(soupSession, (result is null) ? null : result.getAsyncResultStruct(), &err); 947 948 if (err !is null) 949 { 950 throw new GException( new ErrorG(err) ); 951 } 952 953 if(__p is null) 954 { 955 return null; 956 } 957 958 return ObjectG.getDObject!(WebsocketConnection)(cast(SoupWebsocketConnection*) __p, true); 959 } 960 961 /** 962 * Checks if @msg contains a response that would cause @session to 963 * redirect it to a new URL (ignoring @msg's %SOUP_MESSAGE_NO_REDIRECT 964 * flag, and the number of times it has already been redirected). 965 * 966 * Params: 967 * msg = a #SoupMessage that has response headers 968 * 969 * Returns: whether @msg would be redirected 970 * 971 * Since: 2.38 972 */ 973 public bool wouldRedirect(Message msg) 974 { 975 return soup_session_would_redirect(soupSession, (msg is null) ? null : msg.getMessageStruct()) != 0; 976 } 977 978 /** 979 * Emitted when the session requires authentication. If 980 * credentials are available call soup_auth_authenticate() on 981 * @auth. If these credentials fail, the signal will be 982 * emitted again, with @retrying set to %TRUE, which will 983 * continue until you return without calling 984 * soup_auth_authenticate() on @auth. 985 * 986 * Note that this may be emitted before @msg's body has been 987 * fully read. 988 * 989 * If you call soup_session_pause_message() on @msg before 990 * returning, then you can authenticate @auth asynchronously 991 * (as long as you g_object_ref() it to make sure it doesn't 992 * get destroyed), and then unpause @msg when you are ready 993 * for it to continue. 994 * 995 * Params: 996 * msg = the #SoupMessage being sent 997 * auth = the #SoupAuth to authenticate 998 * retrying = %TRUE if this is the second (or later) attempt 999 */ 1000 gulong addOnAuthenticate(void delegate(Message, Auth, bool, Session) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 1001 { 1002 return Signals.connect(this, "authenticate", dlg, connectFlags ^ ConnectFlags.SWAPPED); 1003 } 1004 1005 /** 1006 * Emitted when a new connection is created. This is an 1007 * internal signal intended only to be used for debugging 1008 * purposes, and may go away in the future. 1009 * 1010 * Params: 1011 * connection = the connection 1012 * 1013 * Since: 2.30 1014 */ 1015 gulong addOnConnectionCreated(void delegate(ObjectG, Session) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 1016 { 1017 return Signals.connect(this, "connection-created", dlg, connectFlags ^ ConnectFlags.SWAPPED); 1018 } 1019 1020 /** 1021 * Emitted when a request is queued on @session. (Note that 1022 * "queued" doesn't just mean soup_session_queue_message(); 1023 * soup_session_send_message() implicitly queues the message 1024 * as well.) 1025 * 1026 * When sending a request, first #SoupSession::request_queued 1027 * is emitted, indicating that the session has become aware of 1028 * the request. 1029 * 1030 * Once a connection is available to send the request on, the 1031 * session emits #SoupSession::request_started. Then, various 1032 * #SoupMessage signals are emitted as the message is 1033 * processed. If the message is requeued, it will emit 1034 * #SoupMessage::restarted, which will then be followed by 1035 * another #SoupSession::request_started and another set of 1036 * #SoupMessage signals when the message is re-sent. 1037 * 1038 * Eventually, the message will emit #SoupMessage::finished. 1039 * Normally, this signals the completion of message 1040 * processing. However, it is possible that the application 1041 * will requeue the message from the "finished" handler (or 1042 * equivalently, from the soup_session_queue_message() 1043 * callback). In that case, the process will loop back to 1044 * #SoupSession::request_started. 1045 * 1046 * Eventually, a message will reach "finished" and not be 1047 * requeued. At that point, the session will emit 1048 * #SoupSession::request_unqueued to indicate that it is done 1049 * with the message. 1050 * 1051 * To sum up: #SoupSession::request_queued and 1052 * #SoupSession::request_unqueued are guaranteed to be emitted 1053 * exactly once, but #SoupSession::request_started and 1054 * #SoupMessage::finished (and all of the other #SoupMessage 1055 * signals) may be invoked multiple times for a given message. 1056 * 1057 * Params: 1058 * msg = the request that was queued 1059 * 1060 * Since: 2.24 1061 */ 1062 gulong addOnRequestQueued(void delegate(Message, Session) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 1063 { 1064 return Signals.connect(this, "request-queued", dlg, connectFlags ^ ConnectFlags.SWAPPED); 1065 } 1066 1067 /** 1068 * Emitted just before a request is sent. See 1069 * #SoupSession::request_queued for a detailed description of 1070 * the message lifecycle within a session. 1071 * 1072 * Deprecated: Use #SoupMessage::starting instead. 1073 * 1074 * Params: 1075 * msg = the request being sent 1076 * socket = the socket the request is being sent on 1077 */ 1078 gulong addOnRequestStarted(void delegate(Message, Socket, Session) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 1079 { 1080 return Signals.connect(this, "request-started", dlg, connectFlags ^ ConnectFlags.SWAPPED); 1081 } 1082 1083 /** 1084 * Emitted when a request is removed from @session's queue, 1085 * indicating that @session is done with it. See 1086 * #SoupSession::request_queued for a detailed description of the 1087 * message lifecycle within a session. 1088 * 1089 * Params: 1090 * msg = the request that was unqueued 1091 * 1092 * Since: 2.24 1093 */ 1094 gulong addOnRequestUnqueued(void delegate(Message, Session) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 1095 { 1096 return Signals.connect(this, "request-unqueued", dlg, connectFlags ^ ConnectFlags.SWAPPED); 1097 } 1098 1099 /** 1100 * Emitted when an SSL tunnel is being created on a proxy 1101 * connection. This is an internal signal intended only to be 1102 * used for debugging purposes, and may go away in the future. 1103 * 1104 * Params: 1105 * connection = the connection 1106 * 1107 * Since: 2.30 1108 */ 1109 gulong addOnTunneling(void delegate(ObjectG, Session) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 1110 { 1111 return Signals.connect(this, "tunneling", dlg, connectFlags ^ ConnectFlags.SWAPPED); 1112 } 1113 }