Rusty Rob
Rusty Rob

Reputation: 17213

difference between two http requests

I have two http requests, one written in curl, one written in javascript in chrome. The curl request works but the chrome request doesn't, but i'm not sure why.

Chrome:

PUT /api/Account HTTP/1.1
Host: mydomain.co.nz
Connection: keep-alive
Content-Length: 152
Pragma: no-cache
Cache-Control: no-cache
Authorization: Bearer eyJhb..
Origin: http://localhost:4200
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36
Content-Type: multipart/form-data; boundary=--------------------------33e4cd665cd7a003
Accept: application/json
Referer: http://localhost:4200/conversations
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.8

--------------------------33e4cd665cd7a003
Content-Disposition: form-data; name="data"

{"isoncall" : true}
--------------------------33e4cd665cd7a003--

curl:

PUT /api/Account HTTP/1.1
Host: mydomain.co.nz
User-Agent: curl/7.51.0
accept: application/json
authorization: Bearer eyJhbGciO....
cache-control: no-cache
Content-Length: 158
Expect: 100-continue
Content-Type: multipart/form-data; boundary=--------------------
----a8c24af99c272f79

--------------------------a8c24af99c272f79
Content-Disposition: form-data; name="data"

{"isoncall" : true}
--------------------------a8c24af99c272f79--

The error i'm getting with chrome is:

[{"error":"Unexpected end of Stream, the content may have already been read by another component. ","type":"IOException","stack":" at Microsoft.AspNetCore.WebUtilities.MultipartReaderStream.d__41.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at Microsoft.AspNetCore.WebUtilities.StreamHelperExtensions.d__3.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at Microsoft.AspNetCore.WebUtilities.MultipartReader.d__20.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at Microsoft.AspNetCore.Http.Features.FormFeature.d__18.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at Microsoft.AspNetCore.Mvc.ModelBinding.FormValueProviderFactory.d__1.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at Microsoft.AspNetCore.Mvc.ModelBinding.CompositeValueProvider.d__2.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at Microsoft.AspNetCore.Mvc.Internal.DefaultControllerArgumentBinder.d__6.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__22.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ResourceExecutedContext context)\r\n at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)\r\n at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__20.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at Microsoft.AspNetCore.Builder.RouterMiddleware.d__4.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at Microsoft.AspNetCore.Builder.Extensions.MapMiddleware.d__3.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at IdentityModel.AspNetCore.ScopeValidation.ScopeValidationMiddleware.d__3.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware1.<Invoke>d__18.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware1.d__18.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at IdentityServer4.AccessTokenValidation.IdentityServerAuthenticationMiddleware.d__7.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at Microsoft.AspNetCore.Cors.Infrastructure.CorsMiddleware.d__7.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.GetResult()\r\n at Celo.Api.Middleware.Exceptions.ExceptionHandlingMiddleware.d__5.MoveNext() in D:\a\1\s\src\Celo.Api\Middleware\Exceptions\ExceptionHandlingMiddleware.cs:line 41"}]

I'm not sure how this is failing.

for reference the curl command is:

curl -X PUT https://mydomain.co.nz/api/Account -H 'accept: application/json' -H 'authorization: Bearer eyJhb..' -H 'cache-control: no-cache' -F 'data={"isoncall" : true}'

and the javascript call is:

let xhr:XMLHttpRequest = new XMLHttpRequest();
        xhr.onreadystatechange = () => {
            if (xhr.readyState === 4) {
                if (xhr.status === 200) {
                    console.log('200', xhr.response)
                    //resolve(<MyEntity>JSON.parse(xhr.response));
                } else {
                    console.log('err', xhr.response)
                    //reject(xhr.response);
                }
            }
        };

        xhr.open('PUT', 'https://mydomain.co.nz/api/Account', true);
        xhr.setRequestHeader("Accept", "application/json")
        xhr.setRequestHeader("Authorization", this.authService.getAuth())
        xhr.setRequestHeader('Content-Type', 'multipart/form-data; boundary=--------------------------33e4cd665cd7a003')
        xhr.send(`--------------------------33e4cd665cd7a003
Content-Disposition: form-data; name="data"

{"isoncall" : true}
--------------------------33e4cd665cd7a003--`)

Upvotes: 0

Views: 391

Answers (1)

brain99
brain99

Reputation: 893

A clear difference between the two requests is that in your XHR request, you don't prefix the boundary in the body of the request with two dashes as required.

If you look at the request generated by CURL, you will see that the two boundaries have two additional dashes prefixed (when compared to the boundary in the header), as well as two extra dashes suffixed to the last boundary of the body. You don't have the prefixes in your javascript code.

Now, having said that, I can suggest two possible solutions:

  1. Fix your current code - this is possibly a quick fix.

    As mentioned above, you need to add the additional -- prefix to the boundary in the body. Secondly, I would avoid multiline strings the way you have them and use \n as line separator.
    This would result in the following javascript:

    xhr.open('PUT', 'https://mydomain.co.nz/api/Account', true);
    xhr.setRequestHeader("Accept", "application/json");
    xhr.setRequestHeader("Authorization", this.authService.getAuth());
    xhr.setRequestHeader('Content-Type', 'multipart/form-data; boundary=--------------------------33e4cd665cd7a003')
    xhr.send(`----------------------------33e4cd665cd7a003\n' +
        'Content-Disposition: form-data; name="data"\n\n' +
        '{"isoncall" : true}\n\n' +
        '----------------------------33e4cd665cd7a003--');
    
  2. You could also switch to the XHR FormData API and avoid dealing with all this manually.

    var formData = new FormData();
    formData.append("data", '{"isoncall" : true}');
    xhr.open('PUT', 'https://mydomain.co.nz/api/Account', true);
    xhr.setRequestHeader("Accept", "application/json");
    xhr.setRequestHeader("Authorization", this.authService.getAuth());
    xhr.send(formData);
    

Upvotes: 1

Related Questions