merge client/server connection and stream
parent
439e39a688
commit
c87800ed83
@ -1,207 +1,48 @@
|
|||||||
package nghttp2
|
package nghttp2
|
||||||
|
|
||||||
/*
|
|
||||||
#include "_nghttp2.h"
|
|
||||||
*/
|
|
||||||
import "C"
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"errors"
|
||||||
"io"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"time"
|
||||||
"sync"
|
|
||||||
"unsafe"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ClientStream http2 client stream
|
type stream struct {
|
||||||
type ClientStream struct {
|
|
||||||
streamID int
|
streamID int
|
||||||
conn *ClientConn
|
conn *Conn
|
||||||
cdp C.nghttp2_data_provider
|
|
||||||
dp *dataProvider
|
dp *dataProvider
|
||||||
res *http.Response
|
bp *bodyProvider
|
||||||
|
request *http.Request
|
||||||
|
response *http.Response
|
||||||
resch chan *http.Response
|
resch chan *http.Response
|
||||||
errch chan error
|
|
||||||
closed bool
|
|
||||||
lock *sync.Mutex
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read read stream data
|
var _ net.Conn = &stream{}
|
||||||
func (s *ClientStream) Read(buf []byte) (n int, err error) {
|
|
||||||
if s.closed || s.res == nil || s.res.Body == nil {
|
|
||||||
return 0, io.EOF
|
|
||||||
}
|
|
||||||
return s.res.Body.Read(buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write write data to stream
|
func (s *stream) Read(buf []byte) (int, error) {
|
||||||
func (s *ClientStream) Write(buf []byte) (n int, err error) {
|
return 0, errors.New("not implement")
|
||||||
if s.closed {
|
|
||||||
return 0, io.EOF
|
|
||||||
}
|
}
|
||||||
if s.dp != nil {
|
func (s *stream) Write(buf []byte) (int, error) {
|
||||||
return s.dp.Write(buf)
|
if s.conn.isServer {
|
||||||
|
return 0, errors.New("not implement")
|
||||||
}
|
}
|
||||||
return 0, fmt.Errorf("empty data provider")
|
return 0, errors.New("not implement")
|
||||||
}
|
}
|
||||||
|
func (s *stream) Close() error {
|
||||||
// Close close the stream
|
|
||||||
func (s *ClientStream) Close() error {
|
|
||||||
//s.lock.Lock()
|
|
||||||
//defer s.lock.Unlock()
|
|
||||||
if s.closed {
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
s.closed = true
|
func (s *stream) LocalAddr() net.Addr {
|
||||||
err := io.EOF
|
|
||||||
//log.Printf("close stream %d", int(s.streamID))
|
|
||||||
select {
|
|
||||||
case s.errch <- err:
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
if s.res != nil && s.res.Body != nil {
|
|
||||||
s.res.Body.Close()
|
|
||||||
}
|
|
||||||
//log.Println("close stream done")
|
|
||||||
if s.dp != nil {
|
|
||||||
s.dp.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
if s.res != nil && s.res.Request != nil &&
|
|
||||||
s.res.Request.Method == "CONNECT" {
|
|
||||||
//log.Printf("send rst stream for %d", s.streamID)
|
|
||||||
s.conn.lock.Lock()
|
|
||||||
C.nghttp2_submit_rst_stream(s.conn.session, 0, C.int(s.streamID), 0)
|
|
||||||
s.conn.lock.Unlock()
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
func (s *stream) RemoteAddr() net.Addr {
|
||||||
// ServerStream server stream
|
|
||||||
type ServerStream struct {
|
|
||||||
streamID int
|
|
||||||
// headers receive done
|
|
||||||
headersDone bool
|
|
||||||
// is stream_end flag received
|
|
||||||
streamEnd bool
|
|
||||||
// request
|
|
||||||
req *http.Request
|
|
||||||
// response header
|
|
||||||
header http.Header
|
|
||||||
// response statusCode
|
|
||||||
statusCode int
|
|
||||||
// response has send
|
|
||||||
responseSend bool
|
|
||||||
|
|
||||||
// server connection
|
|
||||||
conn *ServerConn
|
|
||||||
|
|
||||||
// data provider
|
|
||||||
dp *dataProvider
|
|
||||||
cdp C.nghttp2_data_provider
|
|
||||||
|
|
||||||
closed bool
|
|
||||||
//buf *bytes.Buffer
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write write data to stream,
|
|
||||||
// implements http.ResponseWriter
|
|
||||||
func (s *ServerStream) Write(buf []byte) (int, error) {
|
|
||||||
if s.closed {
|
|
||||||
return 0, io.EOF
|
|
||||||
}
|
|
||||||
|
|
||||||
if !s.responseSend {
|
|
||||||
s.WriteHeader(http.StatusOK)
|
|
||||||
}
|
|
||||||
return s.dp.Write(buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriteHeader set response code and send reponse,
|
|
||||||
// implements http.ResponseWriter
|
|
||||||
func (s *ServerStream) WriteHeader(code int) {
|
|
||||||
if s.closed {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if s.responseSend {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
s.responseSend = true
|
|
||||||
s.statusCode = code
|
|
||||||
|
|
||||||
var nv = []C.nghttp2_nv{}
|
|
||||||
|
|
||||||
nv = append(nv, newNV(":status", fmt.Sprintf("%d", code)))
|
|
||||||
|
|
||||||
for k, v := range s.header {
|
|
||||||
//log.Println(k, v[0])
|
|
||||||
_k := strings.ToLower(k)
|
|
||||||
if _k == "host" || _k == "connection" || _k == "proxy-connection" ||
|
|
||||||
_k == "transfer-encoding" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
nv = append(nv, newNV(k, v[0]))
|
|
||||||
}
|
|
||||||
|
|
||||||
var dp *dataProvider
|
|
||||||
|
|
||||||
dp = newDataProvider(unsafe.Pointer(&s.cdp), s.conn.lock, 0)
|
|
||||||
dp.streamID = s.streamID
|
|
||||||
dp.session = s.conn.session
|
|
||||||
|
|
||||||
s.dp = dp
|
|
||||||
|
|
||||||
s.conn.lock.Lock()
|
|
||||||
ret := C._nghttp2_submit_response(
|
|
||||||
s.conn.session, C.int(s.streamID),
|
|
||||||
C.size_t(uintptr(unsafe.Pointer(&nv[0]))),
|
|
||||||
C.size_t(len(nv)), &s.cdp)
|
|
||||||
s.conn.lock.Unlock()
|
|
||||||
|
|
||||||
if int(ret) < 0 {
|
|
||||||
panic(fmt.Sprintf("sumit response error %s",
|
|
||||||
C.GoString(C.nghttp2_strerror(ret))))
|
|
||||||
}
|
|
||||||
//log.Printf("stream %d send response", s.streamID)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Header return the http.Header,
|
|
||||||
// implements http.ResponseWriter
|
|
||||||
func (s *ServerStream) Header() http.Header {
|
|
||||||
if s.header == nil {
|
|
||||||
s.header = http.Header{}
|
|
||||||
}
|
|
||||||
return s.header
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close close the stream
|
|
||||||
func (s *ServerStream) Close() error {
|
|
||||||
if s.closed {
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
s.closed = true
|
func (s *stream) SetDeadline(t time.Time) error {
|
||||||
|
return errors.New("not implement")
|
||||||
if s.req.Body != nil {
|
|
||||||
s.req.Body.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
if s.dp != nil {
|
|
||||||
s.dp.Close()
|
|
||||||
//s.dp = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if s.req.Method == "CONNECT" {
|
|
||||||
s.conn.lock.Lock()
|
|
||||||
s.conn.lock.Unlock()
|
|
||||||
|
|
||||||
if _, ok := s.conn.streams[s.streamID]; ok {
|
|
||||||
//log.Printf("send rst stream %d", s.streamID)
|
|
||||||
C.nghttp2_submit_rst_stream(s.conn.session, 0, C.int(s.streamID), 0)
|
|
||||||
delete(s.conn.streams, s.streamID)
|
|
||||||
}
|
}
|
||||||
|
func (s *stream) SetReadDeadline(t time.Time) error {
|
||||||
|
return errors.New("not implement")
|
||||||
}
|
}
|
||||||
//log.Printf("stream %d closed", s.streamID)
|
func (s *stream) SetWriteDeadline(t time.Time) error {
|
||||||
return nil
|
return errors.New("not implement")
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue