angular: Angular 2.0.0 generates invalid Content-Type header for multipart/form-data requests if a default Content-Type header is configured

I’m submitting a … (check one with “x”)

[X] bug report => search github for a similar issue or PR before submitting
[ ] feature request
[ ] support request => Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question

Current behavior If defaultOptions with header Content-Type is set for http, firing a post request with a FormData body and with header Content-Type null or “” leads to the generation of a corrupt Content-Type header. The Content-Header includes a comma: content-type:, multipart/form-data; boundary=----WebKitFormBoundarylBX4sMHGfDQcsyPM.

Expected behavior Passing an empty Content-Type header triggers angular’s multipart/form-data routines if the body is a FormData object. Without the defaultOptions, the Content-Type header generation works correctly. The Content-Type header generation should not insert a comma if the header Content-Type is set in the http defaultOptions.

Reproduction of the problem See https://github.com/Nick-Triller/angular2-typescript-webpack

Relevant files:

  • app/app.component.ts
  • app/app.module.ts
  • app/http-interceptor.ts

app.module.ts:

import {NgModule}      from '@angular/core';
import {BrowserModule} from '@angular/platform-browser';
import {HttpModule, RequestOptions, XHRBackend, Http} from '@angular/http';

import {AppComponent}  from './app.component';
import {HttpInterceptor} from "./http-interceptor";

@NgModule({
    imports: [
        BrowserModule,
        HttpModule
    ],
    declarations: [
        AppComponent
    ],
    providers: [
        // HttpInterceptor
        {
            provide: Http,
            useFactory:
                (xhrBackend: XHRBackend, requestOptions: RequestOptions) =>
                    new HttpInterceptor(xhrBackend, requestOptions),
            deps: [XHRBackend, RequestOptions]
        }
    ],
    bootstrap: [
        AppComponent
    ]
})

export class AppModule {}

app.component.ts:

/// <reference path="../typings/index.d.ts" />

import {Component} from '@angular/core';
import {Http, RequestOptionsArgs, RequestOptions, Headers} from "@angular/http";

@Component({
    selector: 'my-app',
    template: `
<input type="file" (change)="filePicked($event)" style="width: 100%">
<button (click)="reproduceBug()">Reproduce bug</button>
`
})

export class AppComponent {
    file: File;

    constructor(private http: Http) {
    }

    reproduceBug() {
        const url = "url";

        let fileReader: FileReader = new FileReader();
        let body = new FormData();

        fileReader.addEventListener("load", $event => {
            body.append("file", fileReader.result);
            let options: RequestOptionsArgs = new RequestOptions();
            options.headers = new Headers();
            options.headers.append("Content-Type", "");

            return this.http.post(url, body, options)
                .toPromise();
        });

        // async
        fileReader.readAsBinaryString(this.file);
    }

    filePicked($event) {
        this.file = $event.target.files[0];
    }
}

http-interceptor.ts

import {ConnectionBackend, Http, Request, RequestOptionsArgs, Response, RequestOptions, Headers} from "@angular/http";
import {Injectable} from "@angular/core";

import "./rxjs-extensions";
import {Observable} from "rxjs/Observable";

/**
 * Sets RequestOptions
 */
@Injectable()
export class HttpInterceptor extends Http {

    constructor(backend: ConnectionBackend, defaultOptions: RequestOptions) {
        super(backend, defaultOptions);
        // defaultOptions get merged into other options that are passed into request functions
        defaultOptions.headers = new Headers();
        defaultOptions.headers.append('Content-Type', 'application/json');
    }
}

What is the motivation / use case for changing the behavior? It should be possible to set default Content-Type header and still send multipart/form-data requests.

Please tell us about your environment: Windows 7, Webstorm IDE

Angular version: Angular 2.0.0

Browser: Tested with Firefox 43.0.1 (NO corrupt header) and with Chrome 53.0.2785.116 m (64-bit) with disabled extensions and plugins (corrupt header).

Language: Typescript 1.8.10

Node (for AoT issues): No AoT compilation

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Reactions: 1
  • Comments: 15 (6 by maintainers)

Most upvoted comments

I had the same problem! you MUST delete the content type, like this: request.headers.delete(“Content-Type”);

Plunker: https://plnkr.co/edit/Fzo5uD?p=preview

As stated before, the Bug occurs with Chrome 53.0.2785.116 m (64-bit), but not with Firefox 47.0.1. Other browsers or browser versions were not tested.

To reproduce the bug, open the chrome dev tools network tab, pick a file and click the “reproduce bug” button. Check the content-type header for the mutlipart/form-data request. It starts with a comma.

Edit: Changed plunker link

without options.headers.append("Content-Type", ""); works as expected https://plnkr.co/edit/ViTp47ecIN9kiBw23VfL?p=preview