mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-01-06 12:19:37 -06:00
124 lines
3.2 KiB
Go
124 lines
3.2 KiB
Go
package icapclient
|
|
|
|
import (
|
|
"bufio"
|
|
"errors"
|
|
"net/http"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
// Response represents the icap server response data
|
|
type Response struct {
|
|
StatusCode int
|
|
Status string
|
|
PreviewBytes int
|
|
Header http.Header
|
|
ContentRequest *http.Request
|
|
ContentResponse *http.Response
|
|
}
|
|
|
|
var (
|
|
optionValues = map[string]bool{
|
|
PreviewHeader: true,
|
|
MethodsHeader: true,
|
|
AllowHeader: true,
|
|
TransferPreviewHeader: true,
|
|
ServiceHeader: true,
|
|
ISTagHeader: true,
|
|
OptBodyTypeHeader: true,
|
|
MaxConnectionsHeader: true,
|
|
OptionsTTLHeader: true,
|
|
ServiceIDHeader: true,
|
|
TransferIgnoreHeader: true,
|
|
TransferCompleteHeader: true,
|
|
}
|
|
)
|
|
|
|
// ReadResponse converts a Reader to a icapclient Response
|
|
func ReadResponse(b *bufio.Reader) (*Response, error) {
|
|
|
|
resp := &Response{
|
|
Header: make(map[string][]string),
|
|
}
|
|
|
|
scheme := ""
|
|
httpMsg := ""
|
|
for currentMsg, err := b.ReadString('\n'); err == nil || currentMsg != ""; currentMsg, err = b.ReadString('\n') { // keep reading the buffer message which is the http response message
|
|
|
|
if isRequestLine(currentMsg) { // if the current message line if the first line of the message portion(request line)
|
|
ss := strings.Split(currentMsg, " ")
|
|
|
|
if len(ss) < 3 { // must contain 3 words, for example: "ICAP/1.0 200 OK" or "GET /something HTTP/1.1"
|
|
return nil, errors.New(ErrInvalidTCPMsg + ":" + currentMsg)
|
|
}
|
|
|
|
// preparing the scheme below
|
|
|
|
if ss[0] == ICAPVersion {
|
|
scheme = SchemeICAP
|
|
resp.StatusCode, resp.Status, err = getStatusWithCode(ss[1], strings.Join(ss[2:], " "))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
continue
|
|
}
|
|
|
|
if ss[0] == HTTPVersion {
|
|
scheme = SchemeHTTPResp
|
|
httpMsg = ""
|
|
}
|
|
|
|
if strings.TrimSpace(ss[2]) == HTTPVersion { // for a http request message if the scheme version is always at last, for example: GET /something HTTP/1.1
|
|
scheme = SchemeHTTPReq
|
|
httpMsg = ""
|
|
}
|
|
}
|
|
|
|
// preparing the header for ICAP & contents for HTTP messages below
|
|
|
|
if scheme == SchemeICAP {
|
|
if currentMsg == LF || currentMsg == CRLF { // don't want to count the Line Feed as header
|
|
continue
|
|
}
|
|
header, val := getHeaderVal(currentMsg)
|
|
if header == PreviewHeader {
|
|
pb, _ := strconv.Atoi(val)
|
|
resp.PreviewBytes = pb
|
|
}
|
|
resp.Header.Add(header, val)
|
|
}
|
|
|
|
if scheme == SchemeHTTPReq {
|
|
httpMsg += strings.TrimSpace(currentMsg) + CRLF
|
|
bufferEmpty := b.Buffered() == 0
|
|
if currentMsg == CRLF || bufferEmpty { // a CRLF indicates the end of a http message and the buffer check is just in case the buffer eneded with one last message instead of a CRLF
|
|
var erR error
|
|
resp.ContentRequest, erR = http.ReadRequest(bufio.NewReader(strings.NewReader(httpMsg)))
|
|
if erR != nil {
|
|
return nil, erR
|
|
}
|
|
continue
|
|
}
|
|
}
|
|
|
|
if scheme == SchemeHTTPResp {
|
|
httpMsg += strings.TrimSpace(currentMsg) + CRLF
|
|
bufferEmpty := b.Buffered() == 0
|
|
if currentMsg == CRLF || bufferEmpty {
|
|
var erR error
|
|
resp.ContentResponse, erR = http.ReadResponse(bufio.NewReader(strings.NewReader(httpMsg)), resp.ContentRequest)
|
|
if erR != nil {
|
|
return nil, erR
|
|
}
|
|
continue
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return resp, nil
|
|
|
|
}
|