good morning!!!!

Skip to content
Snippets Groups Projects
Verified Commit ad0135e2 authored by a's avatar a
Browse files

delete this

parent fde83467
No related branches found
No related tags found
No related merge requests found
Pipeline #51104 failed with stage
in 3 minutes and 3 seconds
package http
import (
"bufio"
"context"
"encoding/base64"
"errors"
"fmt"
"io"
"mime"
"net/http"
"net/url"
"strings"
"sync"
"gfx.cafe/open/jrpc/pkg/jsonrpc"
"gfx.cafe/open/jrpc/pkg/serverutil"
)
var _ jsonrpc.ReaderWriter = (*Codec)(nil)
// Reusable codec. use Reset()
type Codec struct {
ctx context.Context
cn func()
r *http.Request
w http.ResponseWriter
wr *bufio.Writer
msgs chan *serverutil.Bundle
errCh chan httpError
mu sync.Mutex
i jsonrpc.PeerInfo
}
type httpError struct {
code int
err error
}
func (c *Codec) Reset(w http.ResponseWriter, r *http.Request) {
c.wr = bufio.NewWriter(w)
if w == nil {
c.wr = bufio.NewWriter(io.Discard)
}
c.r = r
c.w = w
c.msgs = make(chan *serverutil.Bundle, 1)
c.errCh = make(chan httpError, 1)
ctx := c.r.Context()
c.ctx, c.cn = context.WithCancel(ctx)
c.doRead()
c.peerInfo()
}
func (c *Codec) peerInfo() {
c.i.Transport = "http"
c.i.RemoteAddr = c.r.RemoteAddr
c.i.HTTP = c.r.Clone(c.r.Context())
}
// gets the peer info
func (c *Codec) PeerInfo() jsonrpc.PeerInfo {
return c.i
}
func (r *Codec) doReadGet() (msg *serverutil.Bundle, err error) {
method_up := r.r.URL.Query().Get("method")
if method_up == "" {
method_up = strings.TrimPrefix(r.r.URL.Path, "/")
}
params, _ := url.QueryUnescape(r.r.URL.Query().Get("params"))
param := []byte(params)
if pb, err := base64.URLEncoding.DecodeString(params); err == nil {
param = pb
}
id := r.r.URL.Query().Get("id")
if id == "" {
id = "1"
}
return &serverutil.Bundle{
Messages: []*jsonrpc.Message{{
ID: jsonrpc.NewId(id),
Method: method_up,
Params: param,
}},
Batch: false,
}, nil
}
func (r *Codec) doReadRPC() (msg *serverutil.Bundle, err error) {
method_up := r.r.URL.Query().Get("method")
if method_up == "" {
method_up = strings.TrimPrefix(r.r.URL.Path, "/")
}
id := r.r.URL.Query().Get("id")
if id == "" {
id = "1"
}
data, err := io.ReadAll(r.r.Body)
if err != nil {
return nil, err
}
return &serverutil.Bundle{
Messages: []*jsonrpc.Message{{
ID: jsonrpc.NewId(id),
Method: method_up,
Params: data,
}},
Batch: false,
}, nil
}
func (r *Codec) doReadPost() (msg *serverutil.Bundle, err error) {
data, err := io.ReadAll(r.r.Body)
if err != nil {
return nil, err
}
return serverutil.ParseBundle(data), nil
}
// validateRequest returns a non-zero response code and error message if the
// request is invalid.
func ValidateRequest(r *http.Request) (int, error) {
if r.Method == http.MethodPut || r.Method == http.MethodDelete {
return http.StatusMethodNotAllowed, errors.New("method not allowed")
}
if r.ContentLength > maxRequestContentLength {
err := fmt.Errorf("content length too large (%d>%d)", r.ContentLength, maxRequestContentLength)
return http.StatusRequestEntityTooLarge, err
}
// Allow OPTIONS (regardless of content-type)
if r.Method == http.MethodOptions {
return 0, nil
}
// Check content-type
if mt, _, err := mime.ParseMediaType(r.Header.Get("content-type")); err == nil {
for _, accepted := range acceptedContentTypes {
if accepted == mt {
return 0, nil
}
}
}
// Invalid content-type ignored for now
return 0, nil
//err := fmt.Errorf("invalid content type, only %s is supported", contentType)
//return http.StatusUnsupportedMediaType, err
}
func (c *Codec) doRead() {
code, err := ValidateRequest(c.r)
if err != nil {
c.errCh <- httpError{
code: code,
err: err,
}
return
}
go func() {
var data *serverutil.Bundle
// TODO: implement eventsource
switch strings.ToUpper(c.r.Method) {
case http.MethodGet:
data, err = c.doReadGet()
case "RPC":
data, err = c.doReadRPC()
case http.MethodPost:
data, err = c.doReadPost()
}
if err != nil {
c.errCh <- httpError{
code: http.StatusInternalServerError,
err: err,
}
return
}
c.msgs <- data
}()
}
func (c *Codec) ReadBatch(ctx context.Context) ([]*jsonrpc.Message, bool, error) {
select {
case ans := <-c.msgs:
return ans.Messages, ans.Batch, nil
case err := <-c.errCh:
http.Error(c.w, err.err.Error(), err.code)
return nil, false, err.err
case <-ctx.Done():
return nil, false, ctx.Err()
case <-c.ctx.Done():
return nil, false, c.ctx.Err()
}
}
// closes the connection
func (c *Codec) Write(p []byte) (n int, err error) {
return c.wr.Write(p)
}
func (c *Codec) Flush() error {
defer c.cn()
err := c.wr.Flush()
if err != nil {
return err
}
return nil
}
func (c *Codec) Close() error {
c.cn()
return nil
}
// Closed returns a channel which is closed when the connection is closed.
func (c *Codec) Closed() <-chan struct{} {
return c.ctx.Done()
}
// RemoteAddr returns the peer address of the connection.
func (c *Codec) RemoteAddr() string {
return c.r.RemoteAddr
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment