Skip to content

Commit 9ab5f61

Browse files
fix: preserve multiple set-cookie headers (#1278)
1 parent e7f1635 commit 9ab5f61

File tree

4 files changed

+35
-39
lines changed

4 files changed

+35
-39
lines changed

src/controllers/historyController.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import * as path from 'path';
66
import { QuickPickItem, window, workspace } from 'vscode';
77
import { HistoricalHttpRequest } from '../models/httpRequest';
88
import { trace } from "../utils/decorator";
9+
import { formatHeaders } from '../utils/misc';
910
import { UserDataManager } from '../utils/userDataManager';
1011

1112
dayjs.extend(relativeTime);
@@ -62,14 +63,7 @@ export class HistoryController {
6263
private async createRequestInTempFile(request: HistoricalHttpRequest): Promise<string> {
6364
const file = await this.createTempFile();
6465
let output = `${request.method.toUpperCase()} ${request.url}${EOL}`;
65-
if (request.headers) {
66-
for (const header in request.headers) {
67-
if (request.headers.hasOwnProperty(header)) {
68-
const value = request.headers[header];
69-
output += `${header}: ${value}${EOL}`;
70-
}
71-
}
72-
}
66+
output += formatHeaders(request.headers);
7367
if (request.body) {
7468
output += `${EOL}${request.body}`;
7569
}

src/utils/misc.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,32 @@ export function removeHeader(headers: RequestHeaders | ResponseHeaders, name: st
3333
}
3434
}
3535

36+
export function formatHeaders(headers: RequestHeaders | ResponseHeaders): string {
37+
let headerString = '';
38+
for (const header in headers) {
39+
if (headers.hasOwnProperty(header)) {
40+
let value = headers[header];
41+
// Handle set-cookie as a special case since multiple entries
42+
// should appear as their own header. For example:
43+
// set-cookie: a=b
44+
// set-cookie: c=d
45+
// Not:
46+
// set-cookie: a=b,c=d
47+
if (header.toLowerCase() === 'set-cookie') {
48+
if (typeof value === 'string') {
49+
value = [value];
50+
}
51+
for (const cookie of <Array<string>>value) {
52+
headerString += `${header}: ${cookie}\n`;
53+
}
54+
} else {
55+
headerString += `${header}: ${value}\n`;
56+
}
57+
}
58+
}
59+
return headerString;
60+
}
61+
3662
export function md5(text: string | Buffer): string {
3763
return crypto.createHash('md5').update(text).digest('hex');
3864
}

src/views/httpResponseTextDocumentView.ts

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import { EOL } from 'os';
22
import { languages, Position, Range, TextDocument, ViewColumn, window, workspace } from 'vscode';
3-
import { RequestHeaders, ResponseHeaders } from '../models/base';
43
import { SystemSettings } from '../models/configurationSettings';
54
import { HttpResponse } from '../models/httpResponse';
65
import { PreviewOption } from '../models/previewOption';
76
import { MimeUtility } from '../utils/mimeUtility';
7+
import { formatHeaders } from '../utils/misc';
88
import { ResponseFormatUtility } from '../utils/responseFormatUtility';
99

1010
export class HttpResponseTextDocumentView {
@@ -49,7 +49,7 @@ export class HttpResponseTextDocumentView {
4949
// for add request details
5050
const request = response.request;
5151
content += `${request.method} ${request.url} HTTP/1.1${EOL}`;
52-
content += this.formatHeaders(request.headers);
52+
content += formatHeaders(request.headers);
5353
if (request.body) {
5454
if (typeof request.body !== 'string') {
5555
request.body = 'NOTE: Request Body From Is File Not Shown';
@@ -62,7 +62,7 @@ export class HttpResponseTextDocumentView {
6262

6363
if (previewOption !== PreviewOption.Body) {
6464
content += `HTTP/${response.httpVersion} ${response.statusCode} ${response.statusMessage}${EOL}`;
65-
content += this.formatHeaders(response.headers);
65+
content += formatHeaders(response.headers);
6666
}
6767

6868
if (previewOption !== PreviewOption.Headers) {
@@ -73,15 +73,6 @@ export class HttpResponseTextDocumentView {
7373
return content;
7474
}
7575

76-
private formatHeaders(headers: RequestHeaders | ResponseHeaders): string {
77-
let headerString = '';
78-
for (const header in headers) {
79-
const value = headers[header] as string;
80-
headerString += `${header}: ${value}${EOL}`;
81-
}
82-
return headerString;
83-
}
84-
8576
private getVSCodeDocumentLanguageId(response: HttpResponse) {
8677
if (this.settings.previewOption === PreviewOption.Body) {
8778
const contentType = response.contentType;

src/views/httpResponseWebview.ts

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
import * as fs from 'fs-extra';
22
import * as os from 'os';
33
import { Clipboard, commands, env, ExtensionContext, Uri, ViewColumn, WebviewPanel, window, workspace } from 'vscode';
4-
import { RequestHeaders, ResponseHeaders } from '../models/base';
54
import { SystemSettings } from '../models/configurationSettings';
65
import { HttpRequest } from '../models/httpRequest';
76
import { HttpResponse } from '../models/httpResponse';
87
import { PreviewOption } from '../models/previewOption';
98
import { trace } from '../utils/decorator';
109
import { disposeAll } from '../utils/dispose';
1110
import { MimeUtility } from '../utils/mimeUtility';
12-
import { base64, getHeader, isJSONString } from '../utils/misc';
11+
import { base64, formatHeaders, getHeader, isJSONString } from '../utils/misc';
1312
import { ResponseFormatUtility } from '../utils/responseFormatUtility';
1413
import { UserDataManager } from '../utils/userDataManager';
1514
import { BaseWebview } from './baseWebview';
@@ -213,7 +212,7 @@ export class HttpResponseWebview extends BaseWebview {
213212

214213
private getFullResponseString(response: HttpResponse): string {
215214
const statusLine = `HTTP/${response.httpVersion} ${response.statusCode} ${response.statusMessage}${os.EOL}`;
216-
const headerString = Object.entries(response.headers).reduce((acc, [name, value]) => acc + `${name}: ${value}${os.EOL}`, '');
215+
const headerString = formatHeaders(response.headers);
217216
const body = response.body ? `${os.EOL}${response.body}` : '';
218217
return `${statusLine}${headerString}${body}`;
219218
}
@@ -284,7 +283,7 @@ export class HttpResponseWebview extends BaseWebview {
284283
// for add request details
285284
const request = response.request;
286285
const requestNonBodyPart = `${request.method} ${request.url} HTTP/1.1
287-
${HttpResponseWebview.formatHeaders(request.headers)}`;
286+
${formatHeaders(request.headers)}`;
288287
code += hljs.highlight('http', requestNonBodyPart + '\r\n').value;
289288
if (request.body) {
290289
if (typeof request.body !== 'string') {
@@ -305,7 +304,7 @@ ${HttpResponseWebview.formatHeaders(request.headers)}`;
305304

306305
if (previewOption !== PreviewOption.Body) {
307306
const responseNonBodyPart = `HTTP/${response.httpVersion} ${response.statusCode} ${response.statusMessage}
308-
${HttpResponseWebview.formatHeaders(response.headers)}`;
307+
${formatHeaders(response.headers)}`;
309308
code += hljs.highlight('http', responseNonBodyPart + (previewOption !== PreviewOption.Headers ? '\r\n' : '')).value;
310309
}
311310

@@ -448,20 +447,6 @@ ${HttpResponseWebview.formatHeaders(response.headers)}`;
448447
return result;
449448
}
450449

451-
private static formatHeaders(headers: RequestHeaders | ResponseHeaders): string {
452-
let headerString = '';
453-
for (const header in headers) {
454-
if (headers.hasOwnProperty(header)) {
455-
let value = headers[header];
456-
if (typeof headers[header] !== 'string') {
457-
value = <string>headers[header];
458-
}
459-
headerString += `${header}: ${value}\n`;
460-
}
461-
}
462-
return headerString;
463-
}
464-
465450
private static getHighlightLanguageAlias(contentType: string | undefined, content: string | null = null): string | null {
466451
if (MimeUtility.isJSON(contentType)) {
467452
return 'json';

0 commit comments

Comments
 (0)