Skip to content
This repository has been archived by the owner on Mar 16, 2019. It is now read-only.

How to add boundary when uploading file to server #105

Closed
siyuan opened this issue Aug 25, 2016 · 11 comments
Closed

How to add boundary when uploading file to server #105

siyuan opened this issue Aug 25, 2016 · 11 comments

Comments

@siyuan
Copy link

siyuan commented Aug 25, 2016

I use the following code to upload file

RNFetchBlob.fetch('POST', 'http://www.example.com/upload-form', {
Authorization : "Bearer access-token",
otherHeader : "foo",
// this is required, otherwise it won't be process as a multipart/form-data request
'Content-Type' : 'multipart/form-data',
},
{
name : 'avatar',
filename : 'avatar.png',
// Change BASE64 encoded data to a file path with prefix RNFetchBlob-file://.
// Or simply wrap the file path with RNFetchBlob.wrap().
data: RNFetchBlob.wrap(PATH_TO_THE_FILE)
}
)

This method fails to upload file because missing boundary. I tried to add boundary after multipart/form-data, still failed to upload.

@wkh237
Copy link
Owner

wkh237 commented Aug 26, 2016

@siyuan , the boundary will be automatically append to Content-Type when body is an array. I'd like to know more information about your environment, does this happens on both Android and IOS ? what's the version of library you're using ? Also, if you can provide a code sample snippet that'd be more helpful 😄

@wkh237
Copy link
Owner

wkh237 commented Aug 26, 2016

I've just tested on both Android and IOS with 0.9.3 using this code snippet

let tmp = null
  // create an image file 
  RNFetchBlob
    .config({ fileCache : true })
    .fetch('GET', `${TEST_SERVER_URL}/public/github.png`)
    .then((res) => {
      tmp = res.path()
      // send multipart request with file
      return RNFetchBlob.fetch('POST', `${TEST_SERVER_URL}/upload-form`, {
        'Content-Type' : 'multipart/form-data'
      }, [
        { name : 'file', filename : 'github.png', data : RNFetchBlob.wrap(tmp) }
      ])
    })
    .then((res) => {
      done()
    })

and here's the log at server

## request headers IOS
{ host: '192.168.0.13:8123',
  'content-type': 'multipart/form-data; charset=utf-8; boundary=RNFetchBlob1507558976',
  expect: '100-continue',
  connection: 'keep-alive',
  accept: '*/*',
  'accept-language': 'en-us',
  'content-length': '24139',
  'accept-encoding': 'gzip, deflate',
  'user-agent': 'RNFetchBlobTest/1 CFNetwork/758.2.8 Darwin/15.6.0' }

## request headers Android
{ 'content-type': 'multipart/form-data; boundary=RNFetchBlob-008f45f3-914d-4c32-bb36-d7888d3c43ca',
  'content-length': '24328',
  host: '192.168.0.13:8123',
  connection: 'Keep-Alive',
  'accept-encoding': 'gzip',
  'user-agent': 'okhttp/3.4.1' }

## parsed multipart data
[ 
{ data: 'issue#105 test' },
{ fieldname: 'file',
    originalname: 'github.png',
    encoding: '7bit',
    mimetype: 'application/octet-stream',
    destination: 'uploads/',
    filename: 'ffa915d7f922928712c7265751398ee2',
    path: 'uploads/ffa915d7f922928712c7265751398ee2',
    size: 23975 } 
]

@siyuan
Copy link
Author

siyuan commented Aug 26, 2016

My code, response.uri is the picture address of other module
RNFetchBlob.fetch('POST', 'http://server/test', {
'Content-Type' : 'multipart/form-data',
},
[
{
name : 'avatar',
filename : 'avatar.png',
data : RNFetchBlob.wrap(response.uri.replace('file://', ''))
}
]
)

tcpdump: 'content-length' is missing.
09:01:05.712134 IP 210-140-71-27.jp-east.compute.idcfcloud.com.44256 > ip-172-31-31-108.ap-northeast-1.compute.internal.webcache: Flags [.], seq 1:1449, ack 1, win 229, options [nop,nop,TS val 3662168511 ecr 3957080846], length 1448
0x0000: 4500 05dc 4a12 4000 3606 0fd7 d28c 471b [email protected].
0x0010: ac1f 1f6c ace0 1f90 b9bb 0ba9 ce43 51df ...l.........CQ.
0x0020: 8010 00e5 3699 0000 0101 080a da48 41bf ....6........HA.
0x0030: ebdc 430e 504f 5354 202f 7465 7374 2048 ..C.POST./test.H
0x0040: 5454 502f 312e 310d 0a43 6f6e 7465 6e74 TTP/1.1..Content
0x0050: 2d54 7970 653a 206d 756c 7469 7061 7274 -Type:.multipart
0x0060: 2f66 6f72 6d2d 6461 7461 3b20 626f 756e /form-data;.boun
0x0070: 6461 7279 3d52 4e46 6574 6368 426c 6f62 dary=RNFetchBlob
0x0080: 2d30 6538 3864 6139 322d 3639 3532 2d34 -0e88da92-6952-4
0x0090: 6235 332d 3839 3963 2d38 3562 6134 3039 b53-899c-85ba409
0x00a0: 3736 3036 340d 0a54 7261 6e73 6665 722d 76064..Transfer-
0x00b0: 456e 636f 6469 6e67 3a20 6368 756e 6b65 Encoding:.chunke
0x00c0: 640d 0a48 6f73 743a 2035 342e 3233 382e d..Host:.54.238.
0x00d0: 3139 312e 3133 303a 3830 3830 0d0a 436f 191.130:8080..Co
0x00e0: 6e6e 6563 7469 6f6e 3a20 4b65 6570 2d41 nnection:.Keep-A
0x00f0: 6c69 7665 0d0a 4163 6365 7074 2d45 6e63 live..Accept-Enc
0x0100: 6f64 696e 673a 2067 7a69 700d 0a55 7365 oding:.gzip..Use
0x0110: 722d 4167 656e 743a 206f 6b68 7474 702f r-Agent:.okhttp/
0x0120: 332e 322e 300d 0a0d 0a32 3030 300d 0a2d 3.2.0....2000..-
0x0130: 2d52 4e46 6574 6368 426c 6f62 2d30 6538 -RNFetchBlob-0e8
0x0140: 3864 6139 322d 3639 3532 2d34 6235 332d 8da92-6952-4b53-
0x0150: 3839 3963 2d38 3562 6134 3039 3736 3036 899c-85ba4097606
0x0160: 340d 0a43 6f6e 7465 6e74 2d44 6973 706f 4..Content-Dispo
0x0170: 7369 7469 6f6e 3a20 666f 726d 2d64 6174 sition:.form-dat
0x0180: 613b 206e 616d 653d 6176 6174 6172 3b20 a;.name=avatar;.
0x0190: 6669 6c65 6e61 6d65 3d61 7661 7461 722e filename=avatar.
0x01a0: 706e 670d 0a43 6f6e 7465 6e74 2d54 7970 png..Content-Typ
0x01b0: 653a 2061 7070 6c69 6361 7469 6f6e 2f6f e:.application/o
0x01c0: 6374 6574 2d73 7472 6561 6d0d 0a0d 0aff ctet-stream.....
0x01d0: d8ff e000 104a 4649 4600 0101 0000 0100 .....JFIF.......
0x01e0: 0100 00ff db00 4300 0101 0101 0101 0101 ......C.........
0x01f0: 0101 0101 0101 0101 0101 0101 0101 0101 ................
0x0200: 0101 0101 0101 0101 0101 0101 0101 0101 ................
0x0210: 0101 0101 0101 0101 0101 0101 0101 0101 ................
0x0220: 0101 0101 0101 0101 ffdb 0043 0101 0101 ...........C....
0x0230: 0101 0101 0101 0101 0101 0101 0101 0101 ................
0x0240: 0101 0101 0101 0101 0101 0101 0101 0101 ................
0x0250: 0101 0101 0101 0101 0101 0101 0101 0101 ................
0x0260: 0101 0101 0101 0101 0101 0101 01ff c000 ................
0x0270: 1108 01f4 0177 0301 2200 0211 0103 1101 .....w..".......
0x0280: ffc4 001f 0000 0105 0101 0101 0101 0000 ................

@wkh237
Copy link
Owner

wkh237 commented Aug 26, 2016

I think the problem is not missing boundary, the request header does not have a Content-Length field, therefore the request stream terminated at incorrect point which also result in missing boundary error.

Besides, I've also noticed that the request is sent using Chunked transfer encoding, which means you're using pre 0.9.2 version of our library. In 0.9.2 we've changed Android HTTP implementation so that all the request no longer uses chunked so there should always be a Content-Length field in headers. (See #94 )

I think you may try install latest version and see if that solves this problem.

$ rnpm uninstall react-native-fetch-blob
$ rnpm install react-native-fetch-blob

Thank you !

@siyuan
Copy link
Author

siyuan commented Aug 26, 2016

Thank you very much.
I encountered another problem. so I still can't upload file.
When I use curl to upload file, my server has this log.
client 114.241.13.67 closed keepalive connection

But when I use react-native-fetch-blob, I can't find this log. Maybe the connection is not closed?

@wkh237
Copy link
Owner

wkh237 commented Aug 26, 2016

Not sure what's the root cause, from my understanding, keepalive connection does not close when task is done, instead it reuses the connection sending multiple request for better perofrmance.

I'm wondering if that's because the Content-Length is smaller than actual size of the body, which makes the server waiting for more data and therefore the upload stream never get closed. Could provide the request headers when you upload data using curl ?

@siyuan
Copy link
Author

siyuan commented Aug 26, 2016

This is the curl tcpdump data. I use tcpdump on my Linux host. not the same picture
09:09:28.843774 IP 114.241.13.67.57734 > ip-172-31-31-108.ap-northeast-1.compute.internal.webcache: Flags [P.], seq 1:220, ack 1, win 229, options [nop,nop,TS val 2855588 ecr 3957583901], length 219
0x0000: 4500 010f 5c3a 4000 3006 a1ef 72f1 0d43 E...:@.0...r..C
0x0010: ac1f 1f6c e186 1f90 427e ce6a 3c7a 5782 ...l....B~.j<zW.
0x0020: 8018 00e5 1c4d 0000 0101 080a 002b 92a4 .....M.......+..
0x0030: ebe3 f01d 504f 5354 202f 7465 7374 2048 ....POST./test.H
0x0040: 5454 502f 312e 310d 0a48 6f73 743a 2035 TTP/1.1..Host:.5
0x0050: 342e 3233 382e 3139 312e 3133 303a 3830 4.238.191.130:80
0x0060: 3830 0d0a 5573 6572 2d41 6765 6e74 3a20 80..User-Agent:.
0x0070: 6375 726c 2f37 2e34 392e 300d 0a41 6363 curl/7.49.0..Acc
0x0080: 6570 743a 202a 2f2a 0d0a 436f 6e74 656e ept:./..Conten
0x0090: 742d 4c65 6e67 7468 3a20 3534 3833 380d t-Length:.54838.
0x00a0: 0a45 7870 6563 743a 2031 3030 2d63 6f6e .Expect:.100-con
0x00b0: 7469 6e75 650d 0a43 6f6e 7465 6e74 2d54 tinue..Content-T
0x00c0: 7970 653a 206d 756c 7469 7061 7274 2f66 ype:.multipart/f
0x00d0: 6f72 6d2d 6461 7461 3b20 626f 756e 6461 orm-data;.bounda
0x00e0: 7279 3d2d 2d2d 2d2d 2d2d 2d2d 2d2d 2d2d ry=-------------
0x00f0: 2d2d 2d2d 2d2d 2d2d 2d2d 2d36 3866 3937 -----------68f97
0x0100: 3432 6636 3337 6535 6633 350d 0a0d 0a 42f637e5f35....

@wkh237
Copy link
Owner

wkh237 commented Aug 26, 2016

Would it possible the problem is the absence of Expect : 100-continue header ? I'm not sure if OkHttp implements this protocol.

Another difference I saw is the Accept-Encoding field, perhaps the server does not support gzip encoding so that it expects a larger request body to be written to the stream. Generally the server does not relys on the Content-Length header since it's not accurate in many cases 😕

@siyuan
Copy link
Author

siyuan commented Aug 26, 2016

Hi,
How did you setup your file server?
Thank you very much.

@wkh237
Copy link
Owner

wkh237 commented Aug 26, 2016

I simply use Express and its middleware multer for testing multipart requests. You can check out the test-server of this project 👍 Also we've tested the multipart request heavily on Firebase.

@siyuan
Copy link
Author

siyuan commented Aug 27, 2016

The root cause of my problem is my server's filename needs "
These code can upload file to my server:

   RNFetchBlob.fetch('POST', 'http://x.y.z.w/test', {
      'Content-Type' : 'multipart/form-data',
    },
    [
      {
        name : "\"avatar\"",
        filename : "\"avatar.jpg\"",
        data : RNFetchBlob.wrap(response.uri.replace('file://', ''))
      }
    ])

@wkh237 wkh237 closed this as completed Sep 11, 2016
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

2 participants