Repository navigation
Expand file tree
/
Copy pathaws-lambda.js
More file actions
131 lines (109 loc) · 3.15 KB
/
Copy pathaws-lambda.js
File metadata and controls
131 lines (109 loc) · 3.15 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
"use strict";
const OPENAI_API_HOST = "api.openai.com";
const HOP_BY_HOP_HEADERS = new Set([
"connection",
"keep-alive",
"proxy-authenticate",
"proxy-authorization",
"te",
"trailer",
"transfer-encoding",
"upgrade",
]);
function getHeader(headers, name) {
const lowerName = name.toLowerCase();
for (const [key, value] of Object.entries(headers || {})) {
if (key.toLowerCase() === lowerName) {
return value;
}
}
return undefined;
}
function appendQueryParams(searchParams, params) {
for (const [key, value] of Object.entries(params || {})) {
if (Array.isArray(value)) {
for (const item of value) {
searchParams.append(key, item);
}
} else if (value !== undefined && value !== null) {
searchParams.append(key, value);
}
}
}
function createUpstreamUrl(event) {
const path = event.rawPath || event.path || "/";
const url = new URL(path, "https://example.com");
if (typeof event.rawQueryString === "string" && event.rawQueryString !== "") {
url.search = event.rawQueryString;
} else if (event.multiValueQueryStringParameters) {
appendQueryParams(url.searchParams, event.multiValueQueryStringParameters);
} else {
appendQueryParams(url.searchParams, event.queryStringParameters);
}
url.protocol = "https:";
url.hostname = OPENAI_API_HOST;
url.port = "";
return url;
}
function createRequestHeaders(headers) {
const requestHeaders = new Headers(headers || {});
requestHeaders.delete("host");
return requestHeaders;
}
function createResponseHeaders(upstreamHeaders) {
const headers = {};
upstreamHeaders.forEach((value, key) => {
if (!HOP_BY_HOP_HEADERS.has(key.toLowerCase())) {
headers[key] = value;
}
});
return headers;
}
function getRequestMethod(event) {
return (
event.requestContext?.http?.method ||
event.httpMethod ||
"GET"
).toUpperCase();
}
function getRequestBody(event) {
if (!event.body) {
return undefined;
}
return event.isBase64Encoded
? Buffer.from(event.body, "base64")
: event.body;
}
exports.handler = async function handler(event) {
try {
const upstreamUrl = createUpstreamUrl(event);
if (upstreamUrl.pathname === "/") {
const host = getHeader(event.headers, "host") || "example.com";
return {
statusCode: 200,
headers: { "content-type": "text/plain; charset=utf-8" },
body: `https://${host}/v1`,
};
}
const method = getRequestMethod(event);
const upstreamResponse = await fetch(upstreamUrl, {
method,
headers: createRequestHeaders(event.headers),
body: method === "GET" || method === "HEAD" ? undefined : getRequestBody(event),
redirect: "follow",
});
const responseBody = Buffer.from(await upstreamResponse.arrayBuffer());
return {
isBase64Encoded: true,
statusCode: upstreamResponse.status,
headers: createResponseHeaders(upstreamResponse.headers),
body: responseBody.toString("base64"),
};
} catch (error) {
return {
statusCode: 500,
headers: { "content-type": "text/plain; charset=utf-8" },
body: error && error.stack ? error.stack : String(error),
};
}
};