Make http client work with non-standard HTTP servers

Shoutcast servers mainly speak http with one important difference: they respond to GETrequests with ICY 200 OKinstead HTTP/1.1 200 OK.

Go will not have it, and with an error it malformed HTTP version "ICY"will be an error.

However, I would like to make everything work, and I wonder what the best approach is. My ideas so far:

  • use custom http.Transport.Proxy to change ICYto HTTP/1.1in-flight
  • outside the proxy of a process that does the same
  • overload http.ParseHTTPVersion(but golang has no function overload)
  • duplicate the entire http package, just to change ParseHTTPVersion

The number 1. seems attractive attractive, but I have no idea how to respect the "scope" of http and actually change all the answers to this http version. Could this be something like http.Transport.Proxy?

Can anyone give me any directions?

+4
source share
1 answer

I got this working by creating a custom dialing function that returns a wrapped connection. My wrapper intercepts the first read in the connection and replaces ICY with HTTP / 1.1. Not super reliable, but proves the concept:

package main

import (
    "fmt"
    "net"
    "net/http"
)

type IcyConnWrapper struct {
    net.Conn
    haveReadAny bool
}

func (i *IcyConnWrapper) Read(b []byte) (int, error) {
    if i.haveReadAny {
        return i.Conn.Read(b)
    }
    i.haveReadAny = true
    //bounds checking ommitted. There are a few ways this can go wrong.
    //always check array sizes and returned n.
    n, err := i.Conn.Read(b[:3])
    if err != nil {
        return n, err
    }
    if string(b[:3]) == "ICY" {
        //write Correct http response into buffer
        copy(b, []byte("HTTP/1.1"))
        return 8, nil
    }
    return n, nil
}

func main() {

    tr := &http.Transport{
        Dial: func(network, a string) (net.Conn, error) {
            realConn, err := net.Dial(network, a)
            if err != nil {
                return nil, err
            }
            return &IcyConnWrapper{Conn: realConn}, nil
        },
    }
    client := &http.Client{Transport: tr}
    http.DefaultClient = client
    resp, err := http.Get("http://178.33.230.189:8100") //random url I found on the internet
    fmt.Println(err)
    fmt.Println(resp.StatusCode)
}
+3
source

Source: https://habr.com/ru/post/1614098/


All Articles