Manipulating HTTP Responses

Discover how to modify and customize HTTP responses before they reach your player. This guide explains how to intercept and adjust response data, headers, and more to tailor the behavior of your application to your exact needs.

When interacting with DRM, HLS Playlist, or other types of media requests, there may be times when you need to adjust the response before it reaches the player.

The preprocessHttpResponse property allows you to define a custom handler that can manipulate these HTTP responses to fit your specific requirements.

In this guide, we’ll explain how this handler works, why you might want to use it, and how to implement it effectively.

What is preprocessHttpResponse?

The preprocessHttpResponse property allows you to assign a custom closure (function) that intercepts and modifies HTTP responses before they are processed by the player. This is particularly useful if you need to alter response data, headers, or other properties to better suit your application’s needs.

Why Would You Want to Modify HTTP Responses?

There are several scenarios where adjusting HTTP responses can be beneficial:

  • Custom Handling for Different Request Types: you may want to process responses differently based on whether they are related to HLS manifests, DRM, subtitles, or other content types.
  • Injecting Custom Data: if a server response is missing certain data, or you need to add specific information, you can do so before the response reaches the player.
  • Modifying Response Data: sometimes, the data returned by the server might need to be transformed or cleaned up before use, such as adjusting URLs or modifying headers.

How to Use preprocessHttpResponse

Using the preprocessHttpResponse property is straightforward. Here’s how you can set it up and start modifying your HTTP responses.

Assign the Handler via a closure

You will assign a closure to the preprocessHttpResponse property of your network config. The closure will conform to the PreprocessHttpResponseHandler type and contain the logic for modifying your responses.

playerConfig.networkConfig.preprocessHttpResponse = { type, response, completionHandler in
    var modifiedResponse = response

    switch type {
    case .manifestHlsVariant:
        // Example: Modify response data for HLS Variant manifests
        modifiedResponse = modifyResponseForHlsVariantType(response)
    case .mediaSubtitles:
        // Example: Inject custom headers for subtitle requests
        modifiedResponse.headers["Custom-Header"] = "SomeValue"
    default:
        break
    }

    // Call the completion handler with the modified response
    completionHandler(modifiedResponse)
}

Understanding the Process

  • Request Type Identification: the type parameter informs you about the nature of the request (e.g., HLS manifest, subtitles). This helps in applying appropriate modifications to the response.
  • Modify the Response: you have full access to the response object, allowing you to change headers, data, or any other properties as needed.
  • Completion Handler: it’s essential to call the completionHandler with your modified response to ensure the changes are passed on to the player.

Practical Example

Imagine you need to adjust the URLs in HLS variant manifest responses to point to a different CDN. Here’s how you could do it:

struct ContentView: View {
    private let player: Player

    init() {
        let playerConfig = PlayerConfig()
        playerConfig.networkConfig.preprocessHttpResponse = { type, response, completionHandler in
            var modifiedResponse = response

            switch type {
            case .manifestHlsVariant:
                // Adjust URLs in the HLS manifest
                modifiedResponse.body = modifyUrlsInHlsManifest(response.body)
            default:
                break
            }

            completionHandler(modifiedResponse)
        }

        player = PlayerFactory.createPlayer(playerConfig: playerConfig)
    }
    ...
}

Now, whenever a manifest request for HLS variants is made, the URLs in the response will be automatically adjusted before the player processes them.

Limitations

While preprocessHttpResponse is powerful, it comes with some limitations:

  • Supported Request Types: currently key HLS AES (key/hls/aes) requests are not supported, and subtitle media (media/subtitles) requests are only supported in case the subtitles are side-loaded. Unsupported requests won’t be processed through this handler.
  • Critical Timing: it’s crucial to call the completionHandler with the modified response. Failing to do so may result in the response not being processed, potentially leading to playback issues.