|
8 | 8 | "fmt"
|
9 | 9 | "io"
|
10 | 10 | "io/ioutil"
|
| 11 | + "mime" |
11 | 12 | "net"
|
12 | 13 | "net/http"
|
13 | 14 | "net/textproto"
|
@@ -566,7 +567,7 @@ func parseQuery(values url.Values) map[string]interface{} {
|
566 | 567 | return nil
|
567 | 568 | }
|
568 | 569 |
|
569 |
| -func parseRequest(perfStandby bool, r *http.Request, w http.ResponseWriter, out interface{}) (io.ReadCloser, error) { |
| 570 | +func parseJSONRequest(perfStandby bool, r *http.Request, w http.ResponseWriter, out interface{}) (io.ReadCloser, error) { |
570 | 571 | // Limit the maximum number of bytes to MaxRequestSize to protect
|
571 | 572 | // against an indefinite amount of data being read.
|
572 | 573 | reader := r.Body
|
@@ -598,6 +599,43 @@ func parseRequest(perfStandby bool, r *http.Request, w http.ResponseWriter, out
|
598 | 599 | return nil, err
|
599 | 600 | }
|
600 | 601 |
|
| 602 | +// parseFormRequest parses values from a form POST. |
| 603 | +// |
| 604 | +// A nil map will be returned if the format is empty or invalid. |
| 605 | +func parseFormRequest(r *http.Request) (map[string]interface{}, error) { |
| 606 | + maxRequestSize := r.Context().Value("max_request_size") |
| 607 | + if maxRequestSize != nil { |
| 608 | + max, ok := maxRequestSize.(int64) |
| 609 | + if !ok { |
| 610 | + return nil, errors.New("could not parse max_request_size from request context") |
| 611 | + } |
| 612 | + if max > 0 { |
| 613 | + r.Body = ioutil.NopCloser(io.LimitReader(r.Body, max)) |
| 614 | + } |
| 615 | + } |
| 616 | + if err := r.ParseForm(); err != nil { |
| 617 | + return nil, err |
| 618 | + } |
| 619 | + |
| 620 | + var data map[string]interface{} |
| 621 | + |
| 622 | + if len(r.PostForm) != 0 { |
| 623 | + data = make(map[string]interface{}, len(r.PostForm)) |
| 624 | + for k, v := range r.PostForm { |
| 625 | + switch len(v) { |
| 626 | + case 0, 1: |
| 627 | + data[k] = v[0] |
| 628 | + default: |
| 629 | + // Almost anywhere taking in a string list can take in comma |
| 630 | + // separated values, and really this is super niche anyways |
| 631 | + data[k] = strings.Join(v, ",") |
| 632 | + } |
| 633 | + } |
| 634 | + } |
| 635 | + |
| 636 | + return data, nil |
| 637 | +} |
| 638 | + |
601 | 639 | // handleRequestForwarding determines whether to forward a request or not,
|
602 | 640 | // falling back on the older behavior of redirecting the client
|
603 | 641 | func handleRequestForwarding(core *vault.Core, handler http.Handler) http.Handler {
|
@@ -960,6 +998,40 @@ func parseMFAHeader(req *logical.Request) error {
|
960 | 998 | return nil
|
961 | 999 | }
|
962 | 1000 |
|
| 1001 | +// isForm tries to determine whether the request should be |
| 1002 | +// processed as a form or as JSON. |
| 1003 | +// |
| 1004 | +// Virtually all existing use cases have assumed processing as JSON, |
| 1005 | +// and there has not been a Content-Type requirement in the API. In order to |
| 1006 | +// maintain backwards compatibility, this will err on the side of JSON. |
| 1007 | +// The request will be considered a form only if: |
| 1008 | +// |
| 1009 | +// 1. The content type is "application/x-www-form-urlencoded" |
| 1010 | +// 2. The start of the request doesn't look like JSON. For this test we |
| 1011 | +// we expect the body to begin with { or [, ignoring leading whitespace. |
| 1012 | +func isForm(head []byte, contentType string) bool { |
| 1013 | + contentType, _, err := mime.ParseMediaType(contentType) |
| 1014 | + |
| 1015 | + if err != nil || contentType != "application/x-www-form-urlencoded" { |
| 1016 | + return false |
| 1017 | + } |
| 1018 | + |
| 1019 | + // Look for the start of JSON or not-JSON, skipping any insignificant |
| 1020 | + // whitespace (per https://tools.ietf.org/html/rfc7159#section-2). |
| 1021 | + for _, c := range head { |
| 1022 | + switch c { |
| 1023 | + case ' ', '\t', '\n', '\r': |
| 1024 | + continue |
| 1025 | + case '[', '{': // JSON |
| 1026 | + return false |
| 1027 | + default: // not JSON |
| 1028 | + return true |
| 1029 | + } |
| 1030 | + } |
| 1031 | + |
| 1032 | + return true |
| 1033 | +} |
| 1034 | + |
963 | 1035 | func respondError(w http.ResponseWriter, status int, err error) {
|
964 | 1036 | logical.RespondError(w, status, err)
|
965 | 1037 | }
|
|
0 commit comments