From 85a48609323c76e3feb64214e517a5eb6a68688f Mon Sep 17 00:00:00 2001 From: Arash Hatami Date: Sun, 27 Aug 2023 18:18:32 +0330 Subject: [PATCH 1/5] Add multipart to config Signed-off-by: Arash Hatami --- config/config.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/config/config.go b/config/config.go index b665a6e1..82ccc89b 100644 --- a/config/config.go +++ b/config/config.go @@ -220,11 +220,18 @@ type HTTPProbe struct { FailIfHeaderNotMatchesRegexp []HeaderMatch `yaml:"fail_if_header_not_matches,omitempty"` Body string `yaml:"body,omitempty"` BodyFile string `yaml:"body_file,omitempty"` + BodyMultipart []Multipart `yaml:"body_multipart,omitempty"` HTTPClientConfig config.HTTPClientConfig `yaml:"http_client_config,inline"` Compression string `yaml:"compression,omitempty"` BodySizeLimit units.Base2Bytes `yaml:"body_size_limit,omitempty"` } +type Multipart struct { + Type string `yaml:"type,omitempty"` + Key string `yaml:"key,omitempty"` + Value string `yaml:"value,omitempty"` +} + type GRPCProbe struct { Service string `yaml:"service,omitempty"` TLS bool `yaml:"tls,omitempty"` From 97a52ba5cbe1812efd6530a6943f4aedd654942f Mon Sep 17 00:00:00 2001 From: Arash Hatami Date: Sun, 27 Aug 2023 18:19:35 +0330 Subject: [PATCH 2/5] Update CONFIGURATION.md Signed-off-by: Arash Hatami --- CONFIGURATION.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CONFIGURATION.md b/CONFIGURATION.md index 7eb36984..71b740d6 100644 --- a/CONFIGURATION.md +++ b/CONFIGURATION.md @@ -25,8 +25,8 @@ modules: ``` - ### `` + ```yml # The protocol over which the probe will take place (http, tcp, dns, icmp, grpc). @@ -45,6 +45,7 @@ modules: ``` ### `` + ```yml # Accepted status codes for this probe. Defaults to 2xx. From ffd677eb9a48262368fdc784c8ba37c67ba86df9 Mon Sep 17 00:00:00 2001 From: Arash Hatami Date: Sun, 27 Aug 2023 18:25:19 +0330 Subject: [PATCH 3/5] Add HTTP multipart config spec Signed-off-by: Arash Hatami --- CONFIGURATION.md | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/CONFIGURATION.md b/CONFIGURATION.md index 71b740d6..0e808d55 100644 --- a/CONFIGURATION.md +++ b/CONFIGURATION.md @@ -158,9 +158,13 @@ modules: [ body: ] # Read the HTTP request body from from a file. - # It is mutually exclusive with `body`. + # It is mutually exclusive with `body` and `body_multipart`. [ body_file: ] + # Read the HTTP request body from from a file. + # It is mutually exclusive with `body` and `body_file`. + [ body_multipart: ] + [ - , ... ] ``` #### `` @@ -171,6 +175,17 @@ regexp: , [ allow_missing: | default = false ] ``` +#### `` + +```yml +# The type of the multipart body part. Valid values are "file" and "text". +type: +# The name of the multipart body part. +key: +# The value of the multipart body part. It can be a file path or a string. +value: +``` + ### `` ```yml From e76f9c39e38613218b734de65fcdce1e2f9369db Mon Sep 17 00:00:00 2001 From: Arash Hatami Date: Sun, 27 Aug 2023 18:25:33 +0330 Subject: [PATCH 4/5] Add HTTP multipart example Signed-off-by: Arash Hatami --- example.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/example.yml b/example.yml index 5e887a54..49b0843e 100644 --- a/example.yml +++ b/example.yml @@ -54,6 +54,18 @@ modules: http: method: POST body_file: "/files/body.txt" + http_post_body_multipart: + prober: http + timeout: 5s + http: + method: POST + body_multipart: + - type: "file" + key: "file" + value: "/files/body.txt" + - type: "text" + key: "name" + value: "arash" http_basic_auth_example: prober: http timeout: 5s From 3a1f817bab130a12ab6c4c720fcc4923d5ecc1cd Mon Sep 17 00:00:00 2001 From: Arash Hatami Date: Sun, 27 Aug 2023 18:25:58 +0330 Subject: [PATCH 5/5] Support multipart to http probe Signed-off-by: Arash Hatami --- prober/http.go | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/prober/http.go b/prober/http.go index 232214c3..7f0bc217 100644 --- a/prober/http.go +++ b/prober/http.go @@ -14,6 +14,7 @@ package prober import ( + "bytes" "compress/flate" "compress/gzip" "context" @@ -21,6 +22,7 @@ import ( "errors" "fmt" "io" + "mime/multipart" "net" "net/http" "net/http/cookiejar" @@ -420,6 +422,56 @@ func ProbeHTTP(ctx context.Context, target string, module config.Module, registr body = body_file } + // If a multipart form is configured, add it to the request. + if httpConfig.BodyMultipart != nil { + var ( + b bytes.Buffer + r io.Reader + ) + w := multipart.NewWriter(&b) + for _, part := range httpConfig.BodyMultipart { + if part.Type == "file" { + r, err = os.Open(part.Value) + if err != nil { + level.Error(logger).Log("msg", "Error reading body file", "err", err) + return + } + } else { + r = strings.NewReader(part.Value) + } + + var fw io.Writer + if x, ok := r.(io.Closer); ok { + defer x.Close() + } + // Add a file field + if x, ok := r.(*os.File); ok { + if fw, err = w.CreateFormFile(part.Key, x.Name()); err != nil { + level.Error(logger).Log("msg", "Error creating request", "err", err) + return + } + } else { + // Add a text fields + if fw, err = w.CreateFormField(part.Key); err != nil { + level.Error(logger).Log("msg", "Error creating request", "err", err) + return + } + } + if _, err = io.Copy(fw, r); err != nil { + level.Error(logger).Log("msg", "Error creating request", "err", err) + return + } + } + // We should close the multipart writer. + // If we don't close it, your request will be missing the terminating boundary. + w.Close() + + body = &b + + // Set the proper content-type header containing the boundary. + httpConfig.Headers["Content-Type"] = w.FormDataContentType() + } + request, err := http.NewRequest(httpConfig.Method, targetURL.String(), body) if err != nil { level.Error(logger).Log("msg", "Error creating request", "err", err)