protected function uploadByChunks( $params ) {
		// Get the file handle for looping, but don't keep it in the request parameters.
		$fileHandle = $params['file'];
		unset( $params['file'] );
		// Track the chunks and offset.
		$chunksDone = 0;
		$params['offset'] = 0;
		while ( true ) {

			// 1. Make the request.
			$params['chunk'] = fread( $fileHandle, $this->chunkSize );
			$contentDisposition = 'form-data; name="chunk"; filename="' . $params['filename'] . '"';
			$request = MultipartRequest::factory()
				->setParams( $params )
				->setAction( 'upload' )
				->setMultipartParams( [
					'chunk' => [ 'headers' => [ 'Content-Disposition' => $contentDisposition ] ],
				] );
			$response = $this->api->postRequest( $request );

			// 2. Deal with the response.
			$chunksDone++;
			$params['offset'] = ( $chunksDone * $this->chunkSize );
			if ( !isset( $response['upload']['filekey'] ) ) {
				// This should never happen. Even the last response still has the filekey.
				throw new Exception( 'Unable to get filekey for chunked upload' );
			}
			$params['filekey'] = $response['upload']['filekey'];
			if ( $response['upload']['result'] === 'Continue' ) {
				// Amend parameters for next upload POST request.
				$params['offset'] = $response['upload']['offset'];
			} else {
				// The final upload POST will be done in self::upload()
				// to commit the upload out of the stash area.
				unset( $params['chunk'], $params['offset'] );
				return $params;
			}
		}
	}