1
0
Fork 0
mirror of https://github.com/gocsaf/csaf.git synced 2025-12-22 05:40:11 +01:00

Add extra http header support to downloader and checker.

This commit is contained in:
Sascha L. Teichmann 2023-01-25 16:45:05 +01:00
parent 732383561b
commit 51fba46893
7 changed files with 117 additions and 41 deletions

View file

@ -19,6 +19,7 @@ import (
"html/template"
"io"
"log"
"net/http"
"os"
"github.com/csaf-poc/csaf_distribution/util"
@ -38,6 +39,7 @@ type options struct {
Verbose bool `long:"verbose" short:"v" description:"Verbose output"`
Rate *float64 `long:"rate" short:"r" description:"The average upper limit of https operations per second"`
Years *uint `long:"years" short:"y" description:"Number of years to look back from now" value-name:"YEARS"`
ExtraHeader http.Header `long:"header" short:"H" description:"One or more extra HTTP header fields"`
clientCerts []tls.Certificate
}

View file

@ -351,24 +351,30 @@ func (p *processor) httpClient() util.Client {
TLSClientConfig: &tlsConfig,
}
var client util.Client
client := util.Client(&hClient)
// Add extra headers.
if len(p.opts.ExtraHeader) > 0 {
client = &util.HeaderClient{
Client: client,
Header: p.opts.ExtraHeader,
}
}
// Add optional URL logging.
if p.opts.Verbose {
client = &util.LoggingClient{Client: &hClient}
} else {
client = &hClient
client = &util.LoggingClient{Client: client}
}
if p.opts.Rate == nil {
p.client = client
return client
}
p.client = &util.LimitingClient{
// Add optional rate limiting.
if p.opts.Rate != nil {
client = &util.LimitingClient{
Client: client,
Limiter: rate.NewLimiter(rate.Limit(*p.opts.Rate), 1),
}
}
p.client = client
return p.client
}

View file

@ -64,24 +64,30 @@ func (d *downloader) httpClient() util.Client {
}
}
var client util.Client
client := util.Client(&hClient)
// Add extra headers.
if len(d.opts.ExtraHeader) > 0 {
client = &util.HeaderClient{
Client: client,
Header: d.opts.ExtraHeader,
}
}
// Add optional URL logging.
if d.opts.Verbose {
client = &util.LoggingClient{Client: &hClient}
} else {
client = &hClient
client = &util.LoggingClient{Client: client}
}
if d.opts.Rate == nil {
d.client = client
return client
}
d.client = &util.LimitingClient{
// Add optional rate limiting.
if d.opts.Rate != nil {
client = &util.LimitingClient{
Client: client,
Limiter: rate.NewLimiter(rate.Limit(*d.opts.Rate), 1),
}
}
d.client = client
return d.client
}

View file

@ -12,6 +12,7 @@ package main
import (
"fmt"
"log"
"net/http"
"os"
"github.com/csaf-poc/csaf_distribution/util"
@ -24,6 +25,7 @@ type options struct {
Version bool `long:"version" description:"Display version of the binary"`
Verbose bool `long:"verbose" short:"v" description:"Verbose output"`
Rate *float64 `long:"rate" short:"r" description:"The average upper limit of https operations per second"`
ExtraHeader http.Header `long:"header" short:"H" description:"One or more extra HTTP header fields"`
}
func errCheck(err error) {

View file

@ -15,13 +15,14 @@ Application Options:
-v, --verbose Verbose output
-r, --rate= The average upper limit of https operations per second
-y, --years=YEARS Number of years to look back from now
-H, --header= One or more extra HTTP header fields
Help Options:
-h, --help Show this help message
```
Usage example:
` ./csaf_checker example.com -f html --rate=5.3 -o check-results.html`
` ./csaf_checker example.com -f html --rate=5.3 -H apikey:SECRET -o check-results.html`
Each performed check has a return type of either 0,1 or 2:
```

View file

@ -4,7 +4,6 @@ A tool to download CSAF content from a specific domain/provider.
### Usage
```
Usage:
csaf_downloader [OPTIONS] domain...
Application Options:
@ -13,6 +12,7 @@ Application Options:
--version Display version of the binary
-v, --verbose Verbose output
-r, --rate= The average upper limit of https operations per second
-H, --header= One or more extra HTTP header fields
Help Options:
-h, --help Show this help message

View file

@ -14,6 +14,7 @@ import (
"log"
"net/http"
"net/url"
"strings"
"golang.org/x/time/rate"
)
@ -38,6 +39,64 @@ type LimitingClient struct {
Limiter *rate.Limiter
}
// HeaderClient adds extra HTTP header fields to the ou going requests.
type HeaderClient struct {
Client
Header http.Header
}
// Do implements the respective method of the [Client] interface.
func (hc *HeaderClient) Do(req *http.Request) (*http.Response, error) {
// Maybe this overly careful but this minimizes
// potential side effects in the caller.
orig := req.Header
defer func() { req.Header = orig }()
// Work on a copy.
req.Header = req.Header.Clone()
for key, values := range hc.Header {
for _, v := range values {
req.Header.Add(key, v)
}
}
return hc.Client.Do(req)
}
// Get implements the respective method of the [Client] interface.
func (hc *HeaderClient) Get(url string) (*http.Response, error) {
req, err := http.NewRequest(http.MethodGet, url, nil)
if err != nil {
return nil, err
}
return hc.Do(req)
}
// Head implements the respective method of the [Client] interface.
func (hc *HeaderClient) Head(url string) (*http.Response, error) {
req, err := http.NewRequest(http.MethodHead, url, nil)
if err != nil {
return nil, err
}
return hc.Do(req)
}
// Post implements the respective method of the [Client] interface.
func (hc *HeaderClient) Post(url, contentType string, body io.Reader) (*http.Response, error) {
req, err := http.NewRequest(http.MethodPost, url, nil)
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", contentType)
return hc.Do(req)
}
// PostForm implements the respective method of the [Client] interface.
func (hc *HeaderClient) PostForm(url string, data url.Values) (*http.Response, error) {
return hc.Post(
url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode()))
}
// Do implements the respective method of the Client interface.
func (lc *LoggingClient) Do(req *http.Request) (*http.Response, error) {
log.Printf("[DO]: %s\n", req.URL.String())