Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS
Mirrored from https://github.com/Slazee/caddy.git
Synced Nov 12, 23:15 UTC
httpcaddyfile: Stricter errors for site and upstream address schemes (#5757)
Co-authored-by: Mohammed Al Sahaf <msaa1990@gmail.com> Co-authored-by: Francis Lavoie <lavofr@gmail.com>
Karun Agarwal committed
Aug 19, 2023 at 16:58 UTC
288216e1fbf25ebe11fcea7c71be526c4cd0dcce
3 files changed
+374
-2
caddyconfig/httpcaddyfile/addresses.go
+11
@@ -197,6 +197,17 @@ func (st *ServerType) listenerAddrsForServerBlockKey(sblock serverBlock, key str
197
}
198
addr = addr.Normalize()
199
200
+ switch addr.Scheme {
201
+ case "wss":
202
+ return nil, fmt.Errorf("the scheme wss:// is only supported in browsers; use https:// instead")
203
+ case "ws":
204
+ return nil, fmt.Errorf("the scheme ws:// is only supported in browsers; use http:// instead")
205
+ case "https", "http", "":
206
+ // Do nothing or handle the valid schemes
207
+ default:
208
+ return nil, fmt.Errorf("unsupported URL scheme %s://", addr.Scheme)
209
+ }
210
+
211
// figure out the HTTP and HTTPS ports; either
212
// use defaults, or override with user config
213
httpPort, httpsPort := strconv.Itoa(caddyhttp.DefaultHTTPPort), strconv.Itoa(caddyhttp.DefaultHTTPSPort)
caddytest/integration/caddyfile_test.go
+349
@@ -135,3 +135,352 @@ func TestReplIndex(t *testing.T) {
135
// act and assert
136
tester.AssertGetResponse("http://localhost:9080/", 200, "")
137
}
138
+
139
+func TestInvalidPrefix(t *testing.T) {
140
+ type testCase struct {
141
+ config, expectedError string
142
+ }
143
+
144
+ failureCases := []testCase{
145
+ {
146
+ config: `wss://localhost`,
147
+ expectedError: `the scheme wss:// is only supported in browsers; use https:// instead`,
148
+ },
149
+ {
150
+ config: `ws://localhost`,
151
+ expectedError: `the scheme ws:// is only supported in browsers; use http:// instead`,
152
+ },
153
+ {
154
+ config: `someInvalidPrefix://localhost`,
155
+ expectedError: "unsupported URL scheme someinvalidprefix://",
156
+ },
157
+ {
158
+ config: `h2c://localhost`,
159
+ expectedError: `unsupported URL scheme h2c://`,
160
+ },
161
+ {
162
+ config: `localhost, wss://localhost`,
163
+ expectedError: `the scheme wss:// is only supported in browsers; use https:// instead`,
164
+ },
165
+ {
166
+ config: `localhost {
167
+ reverse_proxy ws://localhost"
168
+ }`,
169
+ expectedError: `the scheme ws:// is only supported in browsers; use http:// instead`,
170
+ },
171
+ {
172
+ config: `localhost {
173
+ reverse_proxy someInvalidPrefix://localhost"
174
+ }`,
175
+ expectedError: `unsupported URL scheme someinvalidprefix://`,
176
+ },
177
+ }
178
+
179
+ for _, failureCase := range failureCases {
180
+ caddytest.AssertLoadError(t, failureCase.config, "caddyfile", failureCase.expectedError)
181
+ }
182
+}
183
+
184
+func TestValidPrefix(t *testing.T) {
185
+ type testCase struct {
186
+ rawConfig, expectedResponse string
187
+ }
188
+
189
+ successCases := []testCase{
190
+ {
191
+ "localhost",
192
+ `{
193
+ "apps": {
194
+ "http": {
195
+ "servers": {
196
+ "srv0": {
197
+ "listen": [
198
+ ":443"
199
+ ],
200
+ "routes": [
201
+ {
202
+ "match": [
203
+ {
204
+ "host": [
205
+ "localhost"
206
+ ]
207
+ }
208
+ ],
209
+ "terminal": true
210
+ }
211
+ ]
212
+ }
213
+ }
214
+ }
215
+ }
216
+}`,
217
+ },
218
+ {
219
+ "https://localhost",
220
+ `{
221
+ "apps": {
222
+ "http": {
223
+ "servers": {
224
+ "srv0": {
225
+ "listen": [
226
+ ":443"
227
+ ],
228
+ "routes": [
229
+ {
230
+ "match": [
231
+ {
232
+ "host": [
233
+ "localhost"
234
+ ]
235
+ }
236
+ ],
237
+ "terminal": true
238
+ }
239
+ ]
240
+ }
241
+ }
242
+ }
243
+ }
244
+}`,
245
+ },
246
+ {
247
+ "http://localhost",
248
+ `{
249
+ "apps": {
250
+ "http": {
251
+ "servers": {
252
+ "srv0": {
253
+ "listen": [
254
+ ":80"
255
+ ],
256
+ "routes": [
257
+ {
258
+ "match": [
259
+ {
260
+ "host": [
261
+ "localhost"
262
+ ]
263
+ }
264
+ ],
265
+ "terminal": true
266
+ }
267
+ ]
268
+ }
269
+ }
270
+ }
271
+ }
272
+}`,
273
+ },
274
+ {
275
+ `localhost {
276
+ reverse_proxy http://localhost:3000
277
+ }`,
278
+ `{
279
+ "apps": {
280
+ "http": {
281
+ "servers": {
282
+ "srv0": {
283
+ "listen": [
284
+ ":443"
285
+ ],
286
+ "routes": [
287
+ {
288
+ "match": [
289
+ {
290
+ "host": [
291
+ "localhost"
292
+ ]
293
+ }
294
+ ],
295
+ "handle": [
296
+ {
297
+ "handler": "subroute",
298
+ "routes": [
299
+ {
300
+ "handle": [
301
+ {
302
+ "handler": "reverse_proxy",
303
+ "upstreams": [
304
+ {
305
+ "dial": "localhost:3000"
306
+ }
307
+ ]
308
+ }
309
+ ]
310
+ }
311
+ ]
312
+ }
313
+ ],
314
+ "terminal": true
315
+ }
316
+ ]
317
+ }
318
+ }
319
+ }
320
+ }
321
+}`,
322
+ },
323
+ {
324
+ `localhost {
325
+ reverse_proxy https://localhost:3000
326
+ }`,
327
+ `{
328
+ "apps": {
329
+ "http": {
330
+ "servers": {
331
+ "srv0": {
332
+ "listen": [
333
+ ":443"
334
+ ],
335
+ "routes": [
336
+ {
337
+ "match": [
338
+ {
339
+ "host": [
340
+ "localhost"
341
+ ]
342
+ }
343
+ ],
344
+ "handle": [
345
+ {
346
+ "handler": "subroute",
347
+ "routes": [
348
+ {
349
+ "handle": [
350
+ {
351
+ "handler": "reverse_proxy",
352
+ "transport": {
353
+ "protocol": "http",
354
+ "tls": {}
355
+ },
356
+ "upstreams": [
357
+ {
358
+ "dial": "localhost:3000"
359
+ }
360
+ ]
361
+ }
362
+ ]
363
+ }
364
+ ]
365
+ }
366
+ ],
367
+ "terminal": true
368
+ }
369
+ ]
370
+ }
371
+ }
372
+ }
373
+ }
374
+}`,
375
+ },
376
+ {
377
+ `localhost {
378
+ reverse_proxy h2c://localhost:3000
379
+ }`,
380
+ `{
381
+ "apps": {
382
+ "http": {
383
+ "servers": {
384
+ "srv0": {
385
+ "listen": [
386
+ ":443"
387
+ ],
388
+ "routes": [
389
+ {
390
+ "match": [
391
+ {
392
+ "host": [
393
+ "localhost"
394
+ ]
395
+ }
396
+ ],
397
+ "handle": [
398
+ {
399
+ "handler": "subroute",
400
+ "routes": [
401
+ {
402
+ "handle": [
403
+ {
404
+ "handler": "reverse_proxy",
405
+ "transport": {
406
+ "protocol": "http",
407
+ "versions": [
408
+ "h2c",
409
+ "2"
410
+ ]
411
+ },
412
+ "upstreams": [
413
+ {
414
+ "dial": "localhost:3000"
415
+ }
416
+ ]
417
+ }
418
+ ]
419
+ }
420
+ ]
421
+ }
422
+ ],
423
+ "terminal": true
424
+ }
425
+ ]
426
+ }
427
+ }
428
+ }
429
+ }
430
+}`,
431
+ },
432
+ {
433
+ `localhost {
434
+ reverse_proxy localhost:3000
435
+ }`,
436
+ `{
437
+ "apps": {
438
+ "http": {
439
+ "servers": {
440
+ "srv0": {
441
+ "listen": [
442
+ ":443"
443
+ ],
444
+ "routes": [
445
+ {
446
+ "match": [
447
+ {
448
+ "host": [
449
+ "localhost"
450
+ ]
451
+ }
452
+ ],
453
+ "handle": [
454
+ {
455
+ "handler": "subroute",
456
+ "routes": [
457
+ {
458
+ "handle": [
459
+ {
460
+ "handler": "reverse_proxy",
461
+ "upstreams": [
462
+ {
463
+ "dial": "localhost:3000"
464
+ }
465
+ ]
466
+ }
467
+ ]
468
+ }
469
+ ]
470
+ }
471
+ ],
472
+ "terminal": true
473
+ }
474
+ ]
475
+ }
476
+ }
477
+ }
478
+ }
479
+}`,
480
+ },
481
+ }
482
+
483
+ for _, successCase := range successCases {
484
+ caddytest.AssertAdapt(t, successCase.rawConfig, "caddyfile", successCase.expectedResponse)
485
+ }
486
+}
modules/caddyhttp/reverseproxy/caddyfile.go
+14
-2
@@ -155,6 +155,18 @@ func (h *Handler) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
155
// the underlying JSON does not yet support different
156
// transports (protocols or schemes) to each backend,
157
// so we remember the last one we see and compare them
158
+
159
+ switch pa.scheme {
160
+ case "wss":
161
+ return d.Errf("the scheme wss:// is only supported in browsers; use https:// instead")
162
+ case "ws":
163
+ return d.Errf("the scheme ws:// is only supported in browsers; use http:// instead")
164
+ case "https", "http", "h2c", "":
165
+ // Do nothing or handle the valid schemes
166
+ default:
167
+ return d.Errf("unsupported URL scheme %s://", pa.scheme)
168
+ }
169
+
170
if commonScheme != "" && pa.scheme != commonScheme {
171
return d.Errf("for now, all proxy upstreams must use the same scheme (transport protocol); expecting '%s://' but got '%s://'",
172
commonScheme, pa.scheme)
@@ -193,7 +205,7 @@ func (h *Handler) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
205
for _, up := range d.RemainingArgs() {
206
err := appendUpstream(up)
207
if err != nil {
196
- return err
208
+ return fmt.Errorf("parsing upstream '%s': %w", up, err)
209
}
210
}
211
@@ -217,7 +229,7 @@ func (h *Handler) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
229
for _, up := range args {
230
err := appendUpstream(up)
231
if err != nil {
220
- return err
232
+ return fmt.Errorf("parsing upstream '%s': %w", up, err)
233
}
234
}
235