github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/pkg/covermerger/provider_web.go (about)

     1  // Copyright 2024 syzkaller project authors. All rights reserved.
     2  // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
     3  
     4  package covermerger
     5  
     6  import (
     7  	"encoding/base64"
     8  	"errors"
     9  	"fmt"
    10  	"io"
    11  	"net/http"
    12  	"net/url"
    13  	"strings"
    14  )
    15  
    16  type FuncProxyURI func(filePath, commit string) string
    17  
    18  type webGit struct {
    19  	funcProxy FuncProxyURI
    20  }
    21  
    22  func (mr *webGit) GetFileVersions(targetFilePath string, repoCommits ...RepoCommit,
    23  ) (FileVersions, error) {
    24  	res := make(FileVersions)
    25  	for _, repoCommit := range repoCommits {
    26  		fileBytes, err := mr.loadFile(targetFilePath, repoCommit.Repo, repoCommit.Commit)
    27  		// It is ok if some file doesn't exist. It means we have repo FS diff.
    28  		if err == errFileNotFound {
    29  			continue
    30  		}
    31  		if err != nil {
    32  			return nil, fmt.Errorf("failed to loadFile: %w", err)
    33  		}
    34  		res[repoCommit] = string(fileBytes)
    35  	}
    36  	return res, nil
    37  }
    38  
    39  var errFileNotFound = errors.New("file not found")
    40  
    41  func (mr *webGit) loadFile(filePath, repo, commit string) ([]byte, error) {
    42  	var uri string
    43  	if mr.funcProxy != nil {
    44  		uri = mr.funcProxy(filePath, commit)
    45  	} else {
    46  		uri = fmt.Sprintf("%s/plain/%s", repo, filePath)
    47  		if commit != "latest" {
    48  			uri += "?id=" + commit
    49  		}
    50  	}
    51  	u, err := url.Parse(uri)
    52  	if err != nil {
    53  		return nil, fmt.Errorf("failed to parse %v: %w", uri, err)
    54  	}
    55  	u.Scheme = "https"
    56  	uri = u.String()
    57  	resp, err := http.Get(uri)
    58  	if err != nil {
    59  		return nil, fmt.Errorf("failed to http.Get: %w", err)
    60  	}
    61  	defer resp.Body.Close()
    62  
    63  	if resp.StatusCode == 404 {
    64  		return nil, errFileNotFound
    65  	}
    66  	if resp.StatusCode != 200 {
    67  		return nil, fmt.Errorf("error: status %d getting '%s'", resp.StatusCode, uri)
    68  	}
    69  	body, err := io.ReadAll(resp.Body)
    70  	if err != nil {
    71  		return nil, fmt.Errorf("failed to io.ReadAll from body: %w", err)
    72  	}
    73  	if isGerritServer(resp) {
    74  		if body, err = base64.StdEncoding.DecodeString(string(body)); err != nil {
    75  			return nil, fmt.Errorf("base64.StdEncoding.DecodeString: %w", err)
    76  		}
    77  	}
    78  	return body, nil
    79  }
    80  
    81  func isGerritServer(resp *http.Response) bool {
    82  	for _, headerVals := range resp.Header {
    83  		for _, header := range headerVals {
    84  			if strings.Contains(header, "gerrit") {
    85  				return true
    86  			}
    87  		}
    88  	}
    89  	return false
    90  }
    91  
    92  func MakeWebGit(funcProxy FuncProxyURI) FileVersProvider {
    93  	return &webGit{
    94  		funcProxy: funcProxy,
    95  	}
    96  }