mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-01-03 02:39:52 -06:00
110 lines
2.0 KiB
Go
110 lines
2.0 KiB
Go
package icapclient
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"errors"
|
|
"io"
|
|
"net"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
// ICAPConnConfig is the configuration for the icap connection.
|
|
type ICAPConnConfig struct {
|
|
// Timeout is the maximum amount of time a connection will be kept open
|
|
Timeout time.Duration
|
|
}
|
|
|
|
// ICAPConn manages the transport layer for ICAP protocol.
|
|
type ICAPConn struct {
|
|
tcp net.Conn
|
|
mu sync.Mutex
|
|
timeout time.Duration
|
|
}
|
|
|
|
// NewICAPConn creates a new connection configuration.
|
|
func NewICAPConn(conf ICAPConnConfig) (*ICAPConn, error) {
|
|
return &ICAPConn{
|
|
timeout: conf.Timeout,
|
|
}, nil
|
|
}
|
|
|
|
// Connect connects to the ICAP server.
|
|
func (c *ICAPConn) Connect(ctx context.Context, address string) error {
|
|
dialer := net.Dialer{Timeout: c.timeout}
|
|
conn, err := dialer.DialContext(ctx, "tcp", address)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
c.tcp = conn
|
|
|
|
if c.timeout > 0 {
|
|
deadline := time.Now().Add(c.timeout)
|
|
if err := c.tcp.SetDeadline(deadline); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Send sends a request to the ICAP server and reads the response.
|
|
func (c *ICAPConn) Send(in []byte) ([]byte, error) {
|
|
if !c.ok() {
|
|
return nil, ErrInvalidConnection
|
|
}
|
|
|
|
c.mu.Lock()
|
|
defer c.mu.Unlock()
|
|
|
|
_, err := c.tcp.Write(in)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var data []byte
|
|
buf := make([]byte, 4096)
|
|
for {
|
|
n, err := c.tcp.Read(buf)
|
|
if err != nil && !errors.Is(err, io.EOF) {
|
|
return nil, err
|
|
}
|
|
|
|
if errors.Is(err, io.EOF) || n == 0 {
|
|
break
|
|
}
|
|
|
|
data = append(data, buf[:n]...)
|
|
|
|
// Protocol checks for message termination
|
|
{
|
|
if bytes.Equal(data, []byte(icap100ContinueMsg)) {
|
|
break
|
|
}
|
|
|
|
if bytes.HasSuffix(data, []byte(doubleCRLF)) {
|
|
break
|
|
}
|
|
|
|
if bytes.Contains(data, []byte(icap204NoModsMsg)) {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
return data, nil
|
|
}
|
|
|
|
// Close closes the TCP connection.
|
|
func (c *ICAPConn) Close() error {
|
|
if !c.ok() {
|
|
return ErrInvalidConnection
|
|
}
|
|
return c.tcp.Close()
|
|
}
|
|
|
|
func (c *ICAPConn) ok() bool {
|
|
return c != nil && c.tcp != nil
|
|
}
|