Skip to content

Commit

Permalink
[~] switch to new fhttp
Browse files Browse the repository at this point in the history
  • Loading branch information
Noooste committed Feb 10, 2024
1 parent e5aa0a9 commit fdf1542
Show file tree
Hide file tree
Showing 11 changed files with 317 additions and 68 deletions.
211 changes: 211 additions & 0 deletions cookies.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@ package azuretls
import (
"bytes"
http "github.com/Noooste/fhttp"
"golang.org/x/net/http/httpguts"
"net"
"net/textproto"
"strconv"
"strings"
"time"
)

var cookieNameSanitizer = strings.NewReplacer("\n", "-", "\r", "-")
Expand Down Expand Up @@ -37,3 +42,209 @@ func GetCookiesMap(cookies []*http.Cookie) map[string]string {

return result
}

func ReadSetCookies(h http.Header) []*http.Cookie {
cookieCount := len(h["Set-Cookie"])
if cookieCount == 0 {
return []*http.Cookie{}
}
cookies := make([]*http.Cookie, 0, cookieCount)
for _, line := range h["Set-Cookie"] {
parts := strings.Split(textproto.TrimString(line), ";")
if len(parts) == 1 && parts[0] == "" {
continue
}
parts[0] = textproto.TrimString(parts[0])
j := strings.Index(parts[0], "=")
if j < 0 {
continue
}
name, value := parts[0][:j], parts[0][j+1:]
if !isCookieNameValid(name) {
continue
}
value, ok := parseCookieValue(value, true)
if !ok {
continue
}
c := &http.Cookie{
Name: name,
Value: value,
Raw: line,
}
for i := 1; i < len(parts); i++ {
parts[i] = textproto.TrimString(parts[i])
if len(parts[i]) == 0 {
continue
}

attr, val := parts[i], ""
if j := strings.Index(attr, "="); j >= 0 {
attr, val = attr[:j], attr[j+1:]
}
lowerAttr := strings.ToLower(attr)
val, ok = parseCookieValue(val, false)
if !ok {
c.Unparsed = append(c.Unparsed, parts[i])
continue
}
switch lowerAttr {
case "samesite":
lowerVal := strings.ToLower(val)
switch lowerVal {
case "lax":
c.SameSite = http.SameSiteLaxMode
case "strict":
c.SameSite = http.SameSiteStrictMode
case "none":
c.SameSite = http.SameSiteNoneMode
default:
c.SameSite = http.SameSiteDefaultMode
}
continue
case "secure":
c.Secure = true
continue
case "httponly":
c.HttpOnly = true
continue
case "domain":
c.Domain = val
continue
case "max-age":
secs, err := strconv.Atoi(val)
if err != nil || secs != 0 && val[0] == '0' {
break
}
if secs <= 0 {
secs = -1
}
c.MaxAge = secs
continue
case "expires":
c.RawExpires = val
exptime, err := time.Parse(time.RFC1123, val)
if err != nil {
exptime, err = time.Parse("Mon, 02-Jan-2006 15:04:05 MST", val)
if err != nil {
c.Expires = time.Time{}
break
}
}
c.Expires = exptime.UTC()
continue
case "path":
c.Path = val
continue
}
c.Unparsed = append(c.Unparsed, parts[i])
}
cookies = append(cookies, c)
}
return cookies
}

// validCookieDomain reports whether v is a valid cookie domain-value.
func validCookieDomain(v string) bool {
if isCookieDomainName(v) {
return true
}
if net.ParseIP(v) != nil && !strings.Contains(v, ":") {
return true
}
return false
}

// validCookieExpires reports whether v is a valid cookie expires-value.
func validCookieExpires(t time.Time) bool {
// IETF RFC 6265 Section 5.1.1.5, the year must not be less than 1601
return t.Year() >= 1601
}

// isCookieDomainName reports whether s is a valid domain name or a valid
// domain name with a leading dot '.'. It is almost a direct copy of
// package net's isDomainName.
func isCookieDomainName(s string) bool {
if len(s) == 0 {
return false
}
if len(s) > 255 {
return false
}

if s[0] == '.' {
// A cookie a domain attribute may start with a leading dot.
s = s[1:]
}
last := byte('.')
ok := false // Ok once we've seen a letter.
partlen := 0
for i := 0; i < len(s); i++ {
c := s[i]
switch {
default:
return false
case 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z':
// No '_' allowed here (in contrast to package net).
ok = true
partlen++
case '0' <= c && c <= '9':
// fine
partlen++
case c == '-':
// Byte before dash cannot be dot.
if last == '.' {
return false
}
partlen++
case c == '.':
// Byte before dot cannot be dot, dash.
if last == '.' || last == '-' {
return false
}
if partlen > 63 || partlen == 0 {
return false
}
partlen = 0
}
last = c
}
if last == '-' || partlen > 63 {
return false
}

return ok
}

// Disallows illegal characters in cookie value. Ignores illegal character `"`, some cookies have the " value
func validCookieValueByte(b byte) bool {
return 0x20 <= b &&
b < 0x7f &&
// b != '"' &&
b != ';' &&
b != '\\'
}

func parseCookieValue(raw string, allowDoubleQuote bool) (string, bool) {
// Strip the quotes, if present.
if allowDoubleQuote && len(raw) > 1 && raw[0] == '"' && raw[len(raw)-1] == '"' {
raw = raw[1 : len(raw)-1]
}
for i := 0; i < len(raw); i++ {
if !validCookieValueByte(raw[i]) {
return "", false
}
}
return raw, true
}

func isCookieNameValid(raw string) bool {
if raw == "" {
return false
}
return strings.IndexFunc(raw, isNotToken) < 0
}

func isNotToken(r rune) bool {
return !httpguts.IsTokenRune(r)
}
8 changes: 5 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
module github.com/Noooste/azuretls-client

go 1.21
go 1.21.1

require (
github.com/Noooste/fhttp v1.0.6
github.com/Noooste/fhttp v0.0.1
github.com/Noooste/utls v1.2.5
github.com/Noooste/websocket v1.0.1
github.com/Noooste/websocket v1.0.2
github.com/andybalholm/brotli v1.1.0
github.com/bogdanfinn/fhttp v0.5.27
golang.org/x/net v0.21.0
)

require (
github.com/bogdanfinn/utls v1.6.1 // indirect
github.com/cloudflare/circl v1.3.7 // indirect
github.com/klauspost/compress v1.17.6 // indirect
github.com/quic-go/quic-go v0.41.0 // indirect
Expand Down
8 changes: 8 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
github.com/Noooste/fhttp v0.0.1 h1:OOLbtYm1FrWnOSMgBnzEwbLK69oRkbiSRxerUgDprsA=
github.com/Noooste/fhttp v0.0.1/go.mod h1:CMVxKOhNheqJN5HYE4Rlvz2SRdV8Uv7YWmi6OwmB/Bk=
github.com/Noooste/fhttp v1.0.6 h1:E1u8b+GMhRZSuoINNpiXjE1MHUdZMIcs/g4HEjapWLg=
github.com/Noooste/fhttp v1.0.6/go.mod h1:7rH441v5BuOAQ60LPj7Uwinew1bmv7A0q8DryN/YA6s=
github.com/Noooste/utls v1.1.2/go.mod h1:OG1Bui9jXgt8CkFGoUBuD8lQthczDlAp4gHwRtXtpSQ=
Expand All @@ -6,9 +8,15 @@ github.com/Noooste/utls v1.2.5 h1:x7ye66hXXeeMju2redAUSQ5IZBVpTMqX0/C5dHPLpUA=
github.com/Noooste/utls v1.2.5/go.mod h1:MRUEmRiDO6ORKziZ2ObNwMjxy0vRviJ91JF1qVa0loM=
github.com/Noooste/websocket v1.0.1 h1:iVi8f4SyIMgoMMkieK3yKq6f3qu8Gd7EykaaynzOYZw=
github.com/Noooste/websocket v1.0.1/go.mod h1:KkARUMZtYtC2ftS4++9nUhQfaBCg/VJW8mbrrLdq+GY=
github.com/Noooste/websocket v1.0.2 h1:uz7M3YwMwL1jifasO0THH3dutlMG8zdwXSKea4khc4U=
github.com/Noooste/websocket v1.0.2/go.mod h1:GVbo9s+nTXwhYPTnXHeUxOdL78zp8TkQgk6+G3f/aAg=
github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
github.com/bogdanfinn/fhttp v0.5.27 h1:+glR3k8v5nxfUSk7+J3M246zEQ2yadhS0vLq1utK71A=
github.com/bogdanfinn/fhttp v0.5.27/go.mod h1:oJiYPG3jQTKzk/VFmogH8jxjH5yiv2rrOH48Xso2lrE=
github.com/bogdanfinn/utls v1.6.1 h1:dKDYAcXEyFFJ3GaWaN89DEyjyRraD1qb4osdEK89ass=
github.com/bogdanfinn/utls v1.6.1/go.mod h1:VXIbRZaiY/wHZc6Hu+DZ4O2CgTzjhjCg/Ou3V4r/39Y=
github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU=
github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=
github.com/dsnet/compress v0.0.1/go.mod h1:Aw8dCMJ7RioblQeTqt88akK31OvO8Dhf5JflhBbQEHo=
Expand Down
34 changes: 16 additions & 18 deletions http2.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ func applySettings(settings string, tr *http2.Transport) error {
if settings != "0" {
values := strings.Split(settings, ",")

settingsFrame := make([]http2.Setting, 0, len(values))
settingsFrame := make(map[http2.SettingID]uint32, len(values))

var (
id, val uint64
Expand All @@ -100,28 +100,26 @@ func applySettings(settings string, tr *http2.Transport) error {
return fmt.Errorf(invalidSettingsIndex, i, "value")
}

settingsFrame = append(settingsFrame, http2.Setting{
ID: http2.SettingID(id),
Val: uint32(val),
})
settingsFrame[http2.SettingID(id)] = uint32(val)

tr.Settings = settingsFrame
tr.SettingsOrder = append(tr.SettingsOrder, http2.SettingID(id))
}
} else {
tr.Settings = make([]http2.Setting, 0)
tr.Settings = make(map[http2.SettingID]uint32)
}

return nil
}

func applyWindowUpdate(windowUpdate string, tr *http2.Transport) error {
if windowUpdate == "0" {
tr.WindowsUpdateSize = (2 << 15) - 1
tr.ConnectionFlow = (2 << 15) - 1
} else {
if ws, err := strconv.Atoi(windowUpdate); err != nil {
return fmt.Errorf(invalidWindow, windowUpdate)
} else {
tr.WindowsUpdateSize = uint32(ws)
tr.ConnectionFlow = uint32(ws)
}
}

Expand All @@ -131,7 +129,7 @@ func applyWindowUpdate(windowUpdate string, tr *http2.Transport) error {
func applyPriorities(priorities string, tr *http2.Transport) error {
if priorities != "0" {
rawPriorities := strings.Split(priorities, ",")
streamPriorities := make([]http2.StreamPriority, 0, len(rawPriorities))
streamPriorities := make([]http2.Priority, 0, len(rawPriorities))

var (
id, deps, weight int
Expand Down Expand Up @@ -165,8 +163,8 @@ func applyPriorities(priorities string, tr *http2.Transport) error {
return fmt.Errorf(invalidPriority, priority)
}

streamPriorities = append(streamPriorities, http2.StreamPriority{
StreamId: uint32(id),
streamPriorities = append(streamPriorities, http2.Priority{
StreamID: uint32(id),
PriorityParam: http2.PriorityParam{
Weight: uint8(weight - 1),
Exclusive: exclusive,
Expand All @@ -175,10 +173,10 @@ func applyPriorities(priorities string, tr *http2.Transport) error {
})
}

tr.StreamPriorities = streamPriorities
tr.Priorities = streamPriorities

} else {
tr.StreamPriorities = make([]http2.StreamPriority, 0)
tr.Priorities = make([]http2.Priority, 0)
}

return nil
Expand Down Expand Up @@ -207,15 +205,15 @@ func applyPreHeader(preHeader string, h *PHeader, tr *http2.Transport) error {
}
}

tr.HeaderPriorities = defaultHeaderPriorities("")
tr.HeaderPriority = defaultHeaderPriorities("")

for _, setting := range tr.Settings {
switch setting.ID {
for k, v := range tr.Settings {
switch k {
case http2.SettingInitialWindowSize:
tr.InitialWindowSize = setting.Val
tr.InitialWindowSize = v

case http2.SettingHeaderTableSize:
tr.HeaderTableSize = setting.Val
tr.HeaderTableSize = v
}
}

Expand Down
Loading

0 comments on commit fdf1542

Please sign in to comment.