Basically what you do is correct. Looking at redmine docs you linked to, it seems that suffix after the dot in the url denotes type of posted data (.json for JSON, .xml for XML), which agrees with the response you get - Processing by AttachmentsController#upload as XML. I guess maybe there's a bug in docs and to post binary data you should try using http://redmine/uploads url instead of http://redmine/uploads.xml.

Btw, I highly recommend very good and very popular Requests library for http in Python. It's much better than what's in the standard lib (urllib2). It supports authentication as well but I skipped it for brevity here.

import requests
with open('./x.png', 'rb') as f:
    data = f.read()
res = requests.post(url='http://httpbin.org/post',
                    data=data,
                    headers={'Content-Type': 'application/octet-stream'})

# let's check if what we sent is what we intended to send...
import json
import base64

assert base64.b64decode(res.json()['data'][len('data:application/octet-stream;base64,'):]) == data

UPDATE

To find out why this works with Requests but not with urllib2 we have to examine the difference in what's being sent. To see this I'm sending traffic to http proxy (Fiddler) running on port 8888:

Using Requests

import requests

data = 'test data'
res = requests.post(url='http://localhost:8888',
                    data=data,
                    headers={'Content-Type': 'application/octet-stream'})

we see

POST http://localhost:8888/ HTTP/1.1
Host: localhost:8888
Content-Length: 9
Content-Type: application/octet-stream
Accept-Encoding: gzip, deflate, compress
Accept: */*
User-Agent: python-requests/1.0.4 CPython/2.7.3 Windows/Vista

test data

and using urllib2

import urllib2

data = 'test data'    
req = urllib2.Request('http://localhost:8888', data)
req.add_header('Content-Length', '%d' % len(data))
req.add_header('Content-Type', 'application/octet-stream')
res = urllib2.urlopen(req)

we get

POST http://localhost:8888/ HTTP/1.1
Accept-Encoding: identity
Content-Length: 9
Host: localhost:8888
Content-Type: application/octet-stream
Connection: close
User-Agent: Python-urllib/2.7

test data

I don't see any differences which would warrant different behavior you observe. Having said that it's not uncommon for http servers to inspect User-Agent header and vary behavior based on its value. Try to change headers sent by Requests one by one making them the same as those being sent by urllib2 and see when it stops working.

Answer from Piotr Dobrogost on Stack Overflow
🌐
Postman
community.postman.com › help hub
How to send a POST request with binary data as request body? - Help Hub - Postman Community
October 4, 2023 - Hi, I can send a POST request using binary data as a response body successfully using the normal POST request but I wanted to replicate the same behavior using the pre-request script. The only thing I am struggling with is the creation of the request body. For example, let’s say I have a ...
Top answer
1 of 4
104

Basically what you do is correct. Looking at redmine docs you linked to, it seems that suffix after the dot in the url denotes type of posted data (.json for JSON, .xml for XML), which agrees with the response you get - Processing by AttachmentsController#upload as XML. I guess maybe there's a bug in docs and to post binary data you should try using http://redmine/uploads url instead of http://redmine/uploads.xml.

Btw, I highly recommend very good and very popular Requests library for http in Python. It's much better than what's in the standard lib (urllib2). It supports authentication as well but I skipped it for brevity here.

import requests
with open('./x.png', 'rb') as f:
    data = f.read()
res = requests.post(url='http://httpbin.org/post',
                    data=data,
                    headers={'Content-Type': 'application/octet-stream'})

# let's check if what we sent is what we intended to send...
import json
import base64

assert base64.b64decode(res.json()['data'][len('data:application/octet-stream;base64,'):]) == data

UPDATE

To find out why this works with Requests but not with urllib2 we have to examine the difference in what's being sent. To see this I'm sending traffic to http proxy (Fiddler) running on port 8888:

Using Requests

import requests

data = 'test data'
res = requests.post(url='http://localhost:8888',
                    data=data,
                    headers={'Content-Type': 'application/octet-stream'})

we see

POST http://localhost:8888/ HTTP/1.1
Host: localhost:8888
Content-Length: 9
Content-Type: application/octet-stream
Accept-Encoding: gzip, deflate, compress
Accept: */*
User-Agent: python-requests/1.0.4 CPython/2.7.3 Windows/Vista

test data

and using urllib2

import urllib2

data = 'test data'    
req = urllib2.Request('http://localhost:8888', data)
req.add_header('Content-Length', '%d' % len(data))
req.add_header('Content-Type', 'application/octet-stream')
res = urllib2.urlopen(req)

we get

POST http://localhost:8888/ HTTP/1.1
Accept-Encoding: identity
Content-Length: 9
Host: localhost:8888
Content-Type: application/octet-stream
Connection: close
User-Agent: Python-urllib/2.7

test data

I don't see any differences which would warrant different behavior you observe. Having said that it's not uncommon for http servers to inspect User-Agent header and vary behavior based on its value. Try to change headers sent by Requests one by one making them the same as those being sent by urllib2 and see when it stops working.

2 of 4
4

This has nothing to do with a malformed upload. The HTTP error clearly specifies 401 unauthorized, and tells you the CSRF token is invalid. Try sending a valid CSRF token with the upload.

More about csrf tokens here:

What is a CSRF token ? What is its importance and how does it work?

Discussions

How to send binary data in body HTTP POST
Basically I have to download a file from one platform via HTTP Get request and then upload it to another platform with HTTP Post request, but the file has to be in JSON body. I have managed to do it in make.com where I just mapped “data” field (image 1), where data is passed as binary image ... More on community.n8n.io
🌐 community.n8n.io
0
0
June 24, 2022
c++ - Binary data in post request - Stack Overflow
Is that the right way to pass binary data as post-request body? ... Why do you multiply the length with sizeof(int) when you send octects? More on stackoverflow.com
🌐 stackoverflow.com
Download binary data in POST request to a file
I am sending binary data to Phoenix via a POST request. I need to download the received data to a file for further processing (untar, run pdflatex, send link back to the pdf file). How do I so the download? the data comes in from an Elm client, The controller appears to accept the data – ... More on elixirforum.com
🌐 elixirforum.com
0
0
January 12, 2019
How to post request as binary data
You signed out in another tab or window. Reload to refresh your session. You switched accounts on another tab or window. Reload to refresh your session. ... curl -X POST \ -H "Content-Type: image/png" \ --data-binary '@test.png' \ https://xxxx.xxx.xxx/xxxxxx.png More on github.com
🌐 github.com
5
October 9, 2016
🌐
Postman
blog.postman.com › home › sending and debugging binary data in postman requests
Sending and Debugging Binary Data in Postman Requests | Postman Blog
December 16, 2025 - Select the HTTP Method: In Postman, select POST as your HTTP method for your request. Enter the URL: Input the endpoint URL where you are transmitting data. Choose Body tab: Click on the Body tab, and select binary from the dropdown menu.
🌐
n8n
community.n8n.io › questions
How to send binary data in body HTTP POST - Questions - n8n Community
June 24, 2022 - Basically I have to download a file from one platform via HTTP Get request and then upload it to another platform with HTTP Post request, but the file has to be in JSON body. I have managed to do it in make.com where I just mapped “data” field (image 1), where data is passed as binary image ...
🌐
MDN Web Docs
developer.mozilla.org › en-US › docs › Web › API › XMLHttpRequest_API › Sending_and_Receiving_Binary_Data
Sending and Receiving Binary Data - Web APIs | MDN
April 28, 2025 - You can send JavaScript typed arrays as binary data as well. ... // Create a new array with fake data (Consecutive numbers (0 - 255), looping back to 0) const array = new Uint8Array(512).map((v, i) => i); const xhr = new XMLHttpRequest(); xhr.open("POST", url, false); xhr.send(array); This is building a 512-byte array of 8-bit integers and sending it; you can use any binary data you'd like, of course.
🌐
Elixir Forum
elixirforum.com › phoenix forum › questions / help
Download binary data in POST request to a file - Questions / Help - Elixir Programming Language Forum
January 12, 2019 - I am sending binary data to Phoenix via a POST request. I need to download the received data to a file for further processing (untar, run pdflatex, send link back to the pdf file). How do I so the download? the data comes in from an Elm client, The controller appears to accept the data – no errors – but I don’t see the data when I do IO.inspect params
🌐
GitHub
github.com › parnurzeal › gorequest › issues › 112
How to post request as binary data · Issue #112 · parnurzeal/gorequest
October 9, 2016 - You signed out in another tab or window. Reload to refresh your session. You switched accounts on another tab or window. Reload to refresh your session. ... curl -X POST \ -H "Content-Type: image/png" \ --data-binary '@test.png' \ https://xxxx.xxx.xxx/xxxxxx.png
Author   johnzeng
Find elsewhere
🌐
Reddit
reddit.com › r/learnjavascript › any idea how to add the binary data to the body of the request?
r/learnjavascript on Reddit: Any idea how to add the binary data to the body of the request?
October 24, 2022 -

I'm uploading images to an S3 bucket using an API Gateway. The URL generated works fine with binary data in Postman. What I'm having trouble figuring out is, how do I take the file input and pass the image into the body of the request?

I thought I might need to use FileReader to send as binary. (i've never used FileReader so this is probably wrong).

var file = document.getElementById("files").files[0]; 

var reader = new FileReader();  
reader.readAsArrayBuffer(file);

var readerResult;
reader.onload = function() {
    readerResult = reader.result;
};

How do I store my binary data for the following request? (Postman generated)

var myHeaders = new Headers();
myHeaders.append("Content-Type", "image/jpeg");

var file = "<file contents here>";

var requestOptions = {
  method: 'PUT',
  headers: myHeaders,
  body: file, //need to send the file as binary here...
  redirect: 'follow'
};

fetch("https://myURL.amazonaws.com/v1/bucket/myImage.jpg", requestOptions)
  .then(response => response.text())
  .then(result => console.log(result))
  .catch(error => console.log('error', error));
Top answer
1 of 3
57

Will simply sending base64 encoded data work?

There is no need to use base 64 encoding - this will simply increase the number of bytes you must transfer. Mobile operators normally limit mangling of responses to content types that they understand - i.e. images, stylesheets, etc.

How are the HTTP sessions handled?

HTTP sessions are normally handled either via a URL query parameter or via a cookie value. However, from what you have said it doesn't sound like sessions are necessary.

Arbitrary sockets can be kept alive for a long time, but HTTP verbs are usually short lived. Does this mean I will need to create a new connection for each packet of data?

HTTP requests can last for an arbitrarily long period of time, just as for raw TCP sockets. A GET request can last for hours if necessary. You need not create a new connection for each request — take a look at the Connection: Keep-Alive HTTP header.

Or is there a way to send server responses in chunks, over a single connection?

If you don't know the length of the response you can either omit a Content-Length header or, preferably, use the Transfer-Encoding: chunked HTTP header.

In what ways can an ISP proxy mess with the data, or the headers? For example, a proxy can sometimes keep a connection alive, even if the server closes it.

ISPs don't tend to reveal the changes they make to HTTP responses. If you are concerned about this a simple solution would be to encrypt the data and specify a Content-Encoding HTTP header. This would require you to control both the HTTP client and server.

2 of 3
32

If possible, you could just send the data as HTTP requests and responses.

HTTP is perfectly capable of handling binary data: images are sent over HTTP all the time, and they're binary. People upload and download files of arbitrary data types all the time with no problem.

Just give it a mime type of "application/octet-stream" -- which is basically a generic mime type for binary data with no further specification of just what sort -- and any proxies along the way should leave it alone.

Top answer
1 of 2
3

As expected, this is the same as the non-binary request. So, with the results being the same, what exactly is the difference between is passing a binary vs a non-binary request body? Are there any benefits to using binary data? If so, what are some examples when I would want to use binary data instead?

Many questions at once, let's decipher this:

So, with the results being the same, what exactly is the difference between is passing a binary vs a non-binary request body?

This has been mentioned in the comments and also in answers. The difference is that when not using "binary data" parsing might occur changing the meaning of the data (as raw binary data) to something different, like a file to upload or character encoding of the shell (which might apply as well to binary data but then it being less unexpected).

Are there any benefits to using binary data?

Yes, it's more expressive. You more correctly say which data you want to transfer under any circumstances (still modifications of option argument based on your shell rule might still apply).

If so, what are some examples when I would want to use binary data instead?

I'm lazy to provide these, so just do two tests, one with and one without. As you're testing and from your question you're expecting both to be the same. If you encode that expectation in the same test-case, you can add a data-provider and then add regressions when you run over them. These changes will answer your question(s) over time. Point in case is here, that if you can't answer the questiuon and even after feedback from Stackoverflow and other resources, you need to ensure that your expectations are fulfilled, even if these are two at once.

These are your tests. Write them as you understand them. If in error, fix them later. This is what version control is for. If you are in error, your tests will tell you. Use tests for your own needs. That is basically it. You might need to do changes in future as you were wrong. However the tests normally reflect your state of mind at the time you write them. So in this case, your tests should have alreay specified that you don't understand the difference between those two options, so just assert that both do the same thing. Document that by writing your test (but don't skip one option while you think it's the same but you're not really sure it is), and you will write the right test. You can fix tests later if you become aware of a mistake and at that time the change should fully document what you expect should be done. Don't hide your questions, assert the answers wihtin the test instead. A test is easy to run again, so you can easily check what you expect.

2 of 2
3

According to the curl man page:

--data-binary

(HTTP) This posts data exactly as specified with no extra processing whatsoever.

If you start the data with the letter @, the rest should be a filename. Data is posted in a similar manner as -d, --data does, except that newlines and carriage returns are preserved and conversions are never done.

If this option is used several times, the ones following the first will append data as described in -d, --data.

You should not receive base64 encoded data using the --data-binary option. If you do, its not curl related.

Straight to the question - the only benefit I see is that curl will not process the data passed. If you need to preserve newlines etc it makes sense to use it.

🌐
GitHub
github.com › request › request › issues › 2037
How to post send binary data? · Issue #2037 · request/request
January 27, 2016 - I can use curl to send binary data by adding --data-binary option, like curl "http://url.." --data-binary "user=1&pwd=2&msg=消息" However, if I use request module and add ...
Published   Jan 27, 2016
🌐
HTTPie
httpie.io › docs › cli › binary-data
Binary data - HTTPie 3.2.4 (latest) docs
Binary data is suppressed for terminal output, which makes it safe to perform requests to URLs that send back binary data. Binary data is also suppressed in redirected but prettified output.
🌐
AWS
aws.amazon.com › blogs › compute › handling-binary-data-using-amazon-api-gateway-http-apis
Handling binary data using Amazon API Gateway HTTP APIs | Amazon Web Services
April 13, 2021 - The Lambda function receives the image data via the HTTP API POST. The function generates the noise and returns the binary file to the client resulting in an image similar to the following: ... API Gateway HTTP APIs makes it easier to work with both binary and text media types. HTTP API Lambda integration can automatically infer the need for encoding based on the content-type header passed with the request.
🌐
Quora
quora.com › How-does-HTTP-handle-binary-data
How does HTTP handle binary data? - Quora
It makes no difference whether the data is binary or nonbinary; it it just a sequence of bytes starting just after the blank line and continuing to the end of the connection or for as many bytes as specified in the Content-length header.
🌐
Google Groups
groups.google.com › g › zaproxy-users › c › 4EPcVYkMQZw
File upload: Modify a POST HTTP request body with binary data
July 25, 2022 - The upload is a POST request with the real file content-type (e.g. image/png) not multipart and the binary (at least I suppose) file content in the request body. Client side validation is rather strict/rigid so I prefer to intercept and modify the upload request instead of trying to bypass it. My question is how can I modify the original request body (binary data...