Skip to content

[TECH-DEBIT] Add support for handling non-text (binary) responses in the Request classΒ #289

@guibranco

Description

@guibranco

The Request class currently only supports text-based HTTP requests and responses (e.g., JSON, HTML, or plain text). This creates a limitation when dealing with binary data, such as file uploads and downloads, where the request or response body may contain non-text content.

To address this technical debt and enhance functionality, the Request class should be extended to support handling binary content for both uploads and downloads. This includes updating the class to:

  • Properly handle binary data in HTTP requests and responses.
  • Use headers (e.g., Content-Type and Content-Disposition) to determine the type of content.
  • Provide methods or utilities to facilitate file uploads and downloads.

Acceptance Criteria

  • Extend the Request class to support sending binary data for file uploads.
  • Add support to detect and handle binary responses (e.g., images, PDFs) based on headers (Content-Type).
  • Update the Response class to support binary content (e.g., storing raw binary data in the body property).
  • Ensure the Request class does not decode binary responses as text (e.g., avoid json_decode or string manipulation on binary data).
  • Add unit tests for:
    • File uploads (e.g., POST requests with binary payloads).
    • File downloads (e.g., GET requests for binary content like images or PDFs).
  • Update the documentation to reflect the new capabilities, including examples for uploading and downloading files.

Example

Current Behavior:

$request = new Request();
$response = $request->get("https://example.com/file.jpg");

echo $response->body; // Outputs garbled text due to binary data.

Expected Behavior (File Download):

$request = new Request();
$response = $request->get("https://example.com/file.jpg");

file_put_contents("file.jpg", $response->body); // Properly saves the binary file.

Expected Behavior (File Upload):

$request = new Request();
$response = $request->post("https://example.com/upload", [
    'file' => new CurlFile('path/to/file.jpg', 'image/jpeg', 'file.jpg')
]);

echo $response->status; // Outputs the status of the upload request.

Sample implementation

    /**
     * Downloads a file from a specified URL and saves it to a local path.
     *
     * @param string $url The URL of the file to download.
     * @param string $savePath The local path where the file should be saved.
     * @param array $headers Optional. An array of headers to include in the request.
     * @return bool True if the download is successful, false otherwise.
     */
    public function download(string $url, string $savePath, array $headers = []): bool
    {
        $fields = $this->getFields($url, $headers);
        $fields[CURLOPT_RETURNTRANSFER] = true;
        $fields[CURLOPT_BINARYTRANSFER] = true;

        $curl = curl_init();
        curl_setopt_array($curl, $fields);
        $fileContent = curl_exec($curl);

        if ($fileContent === false) {
            curl_close($curl);
            return false;
        }

        file_put_contents($savePath, $fileContent);
        curl_close($curl);

        return true;
    }

    /**
     * Uploads a file to the specified URL.
     *
     * @param string $url The URL to upload the file to.
     * @param string $filePath The path of the file to upload.
     * @param array $headers Optional. An array of headers to include in the request.
     * @param array $additionalData Optional. Additional data to include in the upload request.
     * @return Response The response from the server.
     */
    public function upload(string $url, string $filePath, array $headers = [], array $additionalData = []): Response
    {
        if (!file_exists($filePath)) {
            throw new RequestException("File not found: {$filePath}");
        }

        $file = new \CURLFile($filePath);
        $postData = array_merge($additionalData, ['file' => $file]);

        $fields = $this->getFields($url, $headers);
        $fields[CURLOPT_CUSTOMREQUEST] = "POST";
        $fields[CURLOPT_POSTFIELDS] = $postData;

        return $this->execute($fields);
    }

Additional Notes

  • Ensure backward compatibility with existing text-based request and response handling.
  • Provide examples and usage notes in the documentation for handling binary uploads and downloads.
  • Add proper error handling for unsupported file types, missing headers, or upload/download failures.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions