Example #1
0
func main() {
	goquic.Initialize()
	goquic.SetLogLevel(logLevel)

	flag.Parse()

	conn, err := goquic.Dial("udp4", host)
	if err != nil {
		panic(err)
	}

	fmt.Println("Connect complete!", conn)

	st := conn.CreateStream()
	fmt.Println("CreateStream complete!", st)
	header := make(http.Header)
	header.Set(":host", "172.24.0.216:8080")
	header.Set(":version", "HTTP/1.0")
	header.Set(":method", "GET")
	header.Set(":path", "/")
	header.Set(":scheme", "http")
	st.WriteHeader(header, false)
	st.Write([]byte("GET / HTTP/1.0\r\n\r\n"))
	st.FinWrite()

	recvHeader, err := st.ReadHeader()
	if err != nil {
		panic(err)
	}
	fmt.Println("Header:", recvHeader)

	buf := make([]byte, 4096)
	n, err := st.Read(buf)
	if err != nil {
		panic(err)
	}
	fmt.Println("Response:", string(buf[:n]))

	n, err = st.Read(buf)
	if err == io.EOF {
		fmt.Println("Received EOF")
	} else if err != nil {
		panic(err)
	} else {
		fmt.Println("Response:", string(buf[:n]))
	}
}
Example #2
0
func (q *QuicRoundTripper) RoundTrip(request *http.Request) (*http.Response, error) {
	if request.Method != "GET" {
		return nil, errors.New("non-GET request is not supported yet. Sorry.")
		// TODO(hodduc): POST / HEAD / PUT support
	}

	var conn *goquic.Conn
	var exists bool

	conn, exists = q.conns[request.Host]
	if !q.keepConnection || !exists {
		conn_new, err := goquic.Dial("udp4", request.Host)
		if err != nil {
			return nil, err
		}

		q.conns[request.Host] = conn_new
		conn = conn_new
	}
	st := conn.CreateStream()

	header := make(http.Header)
	for k, v := range request.Header {
		for _, vv := range v {
			header.Add(k, vv)
		}
	}
	header.Set(":host", request.Host)
	header.Set(":version", request.Proto)
	header.Set(":method", request.Method)
	header.Set(":path", request.URL.RequestURI())
	header.Set(":scheme", request.URL.Scheme)

	if request.Method == "GET" {
		st.WriteHeader(header, true)
	}

	recvHeader, err := st.ReadHeader()
	if err != nil {
		return nil, err
	}

	resp := &http.Response{}
	resp.Status = recvHeader.Get(":status")
	f := strings.SplitN(resp.Status, " ", 3)
	if len(f) < 1 {
		return nil, &badStringError{"malformed HTTP response", resp.Status}
	}
	resp.StatusCode, err = strconv.Atoi(f[0])
	if err != nil {
		return nil, &badStringError{"malformed HTTP status code", f[0]}
	}

	resp.ProtoMajor, resp.ProtoMinor = 2, 0

	resp.Header = recvHeader

	resp.ContentLength, err = strconv.ParseInt(recvHeader.Get("content-length"), 10, 64)
	if err != nil {
		resp.ContentLength = -1
	}
	resp.Request = request

	if q.keepConnection {
		resp.Body = ioutil.NopCloser(st)
	} else {
		// XXX(hodduc): "conn" should be closed after the user reads all response body, so
		// it's hard to determine when to close "conn". So we read all response body prematurely.
		// If response is very big, this could be problematic. (Consider using runtime.finalizer())
		body, err := ioutil.ReadAll(st)
		if err != nil {
			return nil, err
		}
		resp.Body = ioutil.NopCloser(bytes.NewBuffer(body))
		conn.Close()
	}

	return resp, nil
}