New issue
Advanced search Search tips
Note: Color blocks (like or ) mean that a user may not be available. Tooltip shows the reason.

Issue 813285 link

Starred by 5 users

Issue metadata

Status: Unconfirmed
Owner: ----
Cc:
Components:
EstimatedDays: ----
NextAction: ----
OS: Windows
Pri: 2
Type: Bug



Sign in to add a comment

chrome.webRequest.onBeforeRequest - requestBody raw array is often empty

Reported by heber.to...@gmail.com, Feb 17 2018

Issue description

UserAgent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.167 Safari/537.36

Steps to reproduce the problem:
1. create simple extension using chrome.webRequest.onBeforeRequest.addListener.
* Make sure to enable "requestBody".
* You may use the attached file.
2. Run the extension.
3. Go to a website where it's allowed to upload a file (e.g. Dropbox).
4. Upload a file (a simple 20 bytes text file will suffice).

What is the expected behavior?
A buffer containing the uploaded file contents.
E.g. if I uploaded a file containing "hello world", I expect to receive a buffer containing "hello world".

What went wrong?
The buffer was not received. Review attached image.

Did this work before? No 

Does this work in other browsers? Yes

Chrome version: 64.0.3282.167  Channel: n/a
OS Version: 6.1 (Windows 7, Windows Server 2008 R2)
Flash Version: 

This works properly on Firefox.
Either it's a bug, or not implemented.
If it's not implemented documentation should be updated.
 
sample.js
759 bytes View Download
i1.png
26.3 KB View Download
Another example when uploading a file to outlook web in Office365.
i2.png
15.6 KB View Download
Same example when uploading a file to outlook web in Office365 - but this time via Firefox.
i3.png
16.6 KB View Download

Comment 3 by woxxom@gmail.com, Feb 17 2018

I think the console in Chrome never showed the contents of ArrayBuffer of request body. However, the data should be actually there, and you can use it in your code. 
Thank you for the suggestion.
I have tried:

 if (details.requestBody && details.requestBody.raw) {
     details.requestBody.raw.forEach(element => {
         console.log(details.requestId);
         console.log(element);
      });
            
 console.log(new Uint8Array(details.requestBody.raw[0]));

"Foreach" does not occur and it returns undefined for the last print.
If it had worked in the past it longer does.

Thank you,
Tomer.

i4.png
27.8 KB View Download
Correction: last line is "console.log(details.requestBody.raw[0]);"
Went over the chromium source code.
I believe the issue is related to the "Content-Type" header.
For example it seems to be working if the Content-Type is set to application/json.

But what about other requests? (e.g. text/plain) or requests that lack content-type? (specifically when uploading files, content-type might be empty).


I've stopped my investigation at the function "SetUploadData" as it's being called from too many locations, debugging will probably be required at this stage.

Hopefully a Chromium active developer will be able to continue the investigation from here.

Thank you,
Tomer.
 
Labels: Needs-Triage-M64
Cc: sindhu.chelamcherla@chromium.org
Components: Platform>Extensions Platform>DevTools>Network
Labels: Triaged-ET
@Reporter: Please provide sample extension to check this issue. This would help in further debugging of the issue from TE end.

Thanks!
Attaching a sample extension:
manifest.json + sample.js

Thank you,
Tomer.
manifest.json
259 bytes View Download
sample.js
818 bytes View Download
Issue confirmed in Linux as well. So I'm guessing this affects all OSes.

Managed to compile chromium - I will try and troubleshoot and hopefully fix the bug.
Here is what I've learned so far.

switch (element.type()) {
      case network::DataElement::TYPE_BYTES:
        element_readers.push_back(
            std::make_unique<BytesElementReader>(body, element));
        break;
      case network::DataElement::TYPE_FILE:
        element_readers.push_back(std::make_unique<FileElementReader>(
            body, file_task_runner, element));
        break;
      case network::DataElement::TYPE_BLOB: {
        DCHECK_EQ(std::numeric_limits<uint64_t>::max(), element.length());
        DCHECK_EQ(0ul, element.offset());
        std::unique_ptr<storage::BlobDataHandle> handle =
            blob_context->GetBlobDataFromUUID(element.blob_uuid());
        element_readers.push_back(
            std::make_unique<storage::UploadBlobElementReader>(
                std::move(handle)));
        break;
      }

TYPE_BYTES seems to be working fine.
But when I upload a file it goes through the TYPE_BLOB use-case which eventually returns an empty body.

Will keep investigating...
When the Webextension calls "ExtractRequestBodyData" (1) the Blob is not ready yet (UploadBlobElementReader is IO_PENDING).
The RawDataPresenter tries to handle the Blob (2) and reached the "NOTIMPLEMENTED();"

Conclusion: Chrome does not fully support request body and I suggest documentation be updated accordingly.

(1)

std::unique_ptr<base::DictionaryValue> ExtractRequestBodyData(
    net::URLRequest* url_request) {
  const net::UploadDataStream* upload_data = url_request->get_upload();
  if (!upload_data ||
      (url_request->method() != "POST" && url_request->method() != "PUT")) {
    return nullptr;
  }

  auto request_body_data = std::make_unique<base::DictionaryValue>();

  // Get the data presenters, ordered by how specific they are.
  ParsedDataPresenter parsed_data_presenter(*url_request);
  RawDataPresenter raw_data_presenter;
  UploadDataPresenter* const presenters[] = {
      &parsed_data_presenter,  // 1: any parseable forms? (Specific to forms.)
      &raw_data_presenter      // 2: any data at all? (Non-specific.)
  };
  // Keys for the results of the corresponding presenters.
  static const char* const kKeys[] = {keys::kRequestBodyFormDataKey,
                                      keys::kRequestBodyRawKey};
  const std::vector<std::unique_ptr<net::UploadElementReader>>* readers =
      upload_data->GetElementReaders();
  bool some_succeeded = false;
  if (readers) {
    for (size_t i = 0; i < arraysize(presenters); ++i) {
      for (const auto& reader : *readers)
        presenters[i]->FeedNext(*reader);
      if (presenters[i]->Succeeded()) {
        request_body_data->Set(kKeys[i], presenters[i]->Result());
        some_succeeded = true;
        break;
      }
    }
  }
  if (!some_succeeded) {
    request_body_data->SetString(keys::kRequestBodyErrorKey, "Unknown error.");
  }

  return request_body_data;
}

(2)

void RawDataPresenter::FeedNext(const net::UploadElementReader& reader) {
  if (!success_)
    return;

  if (reader.AsBytesReader()) {
    const net::UploadBytesElementReader* bytes_reader = reader.AsBytesReader();
    FeedNextBytes(bytes_reader->bytes(), bytes_reader->length());
  } else if (reader.AsFileReader()) {
    // Insert the file path instead of the contents, which may be too large.
    const net::UploadFileElementReader* file_reader = reader.AsFileReader();
    FeedNextFile(file_reader->path().AsUTF8Unsafe());
  } else {
    NOTIMPLEMENTED();
  }
}
Components: -Platform>DevTools>Network
Removing DevTools label since it appears unrelated to DevTools.
Labels: -Hotlist-Interop

Sign in to add a comment