Skip to content

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

@Nick-Triller

Description

@Nick-Triller

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions