ifndef::snippets-dir[]
:snippets-dir: ../../../../manual-snippets/src/test/groovy
:rb-snippets-dir: ../../../../manual-snippets/real-browser/src/test/groovy
:cm-snippets-dir: ../../../../../module/geb-core/src/main/groovy
:ct-snippets-dir: ../../../../../module/geb-core/src/test/groovy
endif::[]
= Direct downloading

Geb features an API that can be used to make direct HTTP requests from the application that is executing the Geb scripts or tests.
This facilitates fine grained requests and downloading content such as PDFs, CSVs, images, etc. into your scripts or tests to then do something with them.

The direct download API works by using {http-url-connection-link}[`java.net.HttpURLConnection`] to directly connect to a URL from the application executing Geb, bypassing WebDriver.

The Direct Download API is provided by the `{download-support-api}` class, which is mixed in to pages and modules (which means you can just call these instance methods directly from anywhere where you
would want to, e.g. drive blocks, in tests/specs, methods on page objects, methods on modules).
Consult the `{download-support-api}` API reference for the various `download*()` methods that are available.

== Downloading example

For example, let's say you are using Geb to exercise a web application that generates PDF documents.
The WebDriver API can only deal with HTML documents.
You want to hit the PDF download link and also do some tests on the downloaded PDF.
The direct download API is there to fill this need.

[source,groovy]
----
include::{snippets-dir}/downloading/DownloadingSpec.groovy[tag=pages,indent=0]
----

[source,groovy]
----
include::{snippets-dir}/downloading/DownloadingSpec.groovy[tag=example,indent=0]
----

Simple enough, but consider what is happening behind the scenes.
Our application required us to log in, which implies some kind of session state.
Geb is using {http-url-connection-link}[`HttpURLConnection`] to get the content and before doing so the cookies from the real browser are being transferred onto the connection allowing it to reuse
the same session.
The PDF download link href may also be relative, and Geb handles this by resolving the link passed to the download function against the browser's current page URL.

== Fine grained request

The Direct Download API can also be used for making fine grained requests which can be useful for testing edge cases or abnormal behavior.

All of the `download*()` methods take an optional closure that can configure the {http-url-connection-link}[`HttpURLConnection`] that will be used to make the request (after the `Cookie` header has
been set).

For example, we could test what happens when we send `application/json` in the `Accept` header.

[source,groovy]
----
include::{snippets-dir}/downloading/FineGrainedRequestSpec.groovy[tag=example,indent=0]
----

[TIP]
====
Before doing something like the above, it's worth considering whether doing such testing via Geb (a browser automation tool) is the right thing to do.
You may find that it's more appropriate to directly use `HttpURLConnection` or a http client library without Geb.
That said, there are scenarios where such fine grained request control can be useful.
====

== Dealing with untrusted certificates

When facing web applications using untrusted (e.g. self-signed) SSL certificates, you will likely get exceptions when trying to use Geb's download API.
By overriding the behavior of the request you can get around this kind of problem.
Using the following code will allow running requests against a server which uses a certificate from the given keystore:

[source,groovy]
----
include::{snippets-dir}/downloading/UntrustedCertificatesSpec.groovy[tag=import,indent=0]

include::{snippets-dir}/downloading/UntrustedCertificatesSpec.groovy[tag=example,indent=0]
----

== Default configuration

In the <<configuration, configuration>>, the default behaviour of the `HttpURLConnection` object can be specified by providing a closure as the `defaultDownloadConfig` property.

The below example configures all requests executed using direct downloading support to carry a `User-Agent` header.

[source,groovy]
----
include::{snippets-dir}/downloading/DownloadingConfigurationSpec.groovy[tag=config,indent=0]
----

This config closure will be run first, so anything set here can be overridden using the fine grained request configuration shown above.

== Proxy configuration

As previously mentioned, the direct download API uses {http-url-connection-link}[`java.net.HttpURLConnection`] for performing http requests.
This means that it can be configured to use a proxy in the exact same way as `java.net.HttpURLConnection`, that is by link:https://docs.oracle.com/javase/8/docs/api/java/net/doc-files/net-properties.html[setting `http.proxyHost` and `http.proxyPort` system properties]

== Errors

Any I/O type errors that occur during a download operation (e.g. HTTP 500 responses) will result in a link:api/geb/download/DownloadException.html[`DownloadException`] being thrown that wraps the
original exception and provides access to the `HttpURLConnection` used to make the request.
