reusing Body in http.Requests (goproxy)











up vote
5
down vote

favorite
1












Goproxy is a Go package implementing an HTTP proxy.
I am using it to store requests from a client (eg: a web browser) for further processing.



In an http.Request struct, the Body is an io.ReadCloser, it can only be read once.



The problem I faced is that I need to read the Body to store it, but still make it accessible to goproxy so that it can be sent to the server.



I solved it by reading the body with ioutil.ReadAll, and then creating a ReadCloser with the byte slice I got. I then assign this ReadCloser to the request Body.



package main

import (
"bytes"
"flag"
"fmt"
"io/ioutil"
"log"
"net/http"
"net/url"
"regexp"
"sync"

"github.com/elazarl/goproxy"
)

var requests map[string]Request
var mutex sync.Mutex

type Request struct {
Method string
URL url.URL
Proto string // "HTTP/1.0"
ProtoMajor int // 1
ProtoMinor int // 0
Header http.Header
Body byte
ContentLength int64
Host string
PostForm url.Values
RequestURI string
}

type RequestBody struct {
*bytes.Reader
}

func (r RequestBody) Close() error {
return nil
}

func storeRequest(r *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) {
body, err := ioutil.ReadAll(r.Body)
if err != nil {
// only print error for now
log.Println(err)
return r, nil
}
r.Body.Close()
r.Body = RequestBody{bytes.NewReader(body)}
fmt.Println(string(body))
mutex.Lock()
requests[r.URL.Host] = append(requests[r.URL.Host], Request{
Method: r.Method,
URL: *r.URL,
Proto: r.Proto,
ProtoMajor: r.ProtoMajor,
ProtoMinor: r.ProtoMinor,
Header: r.Header,
Body: body,
ContentLength: r.ContentLength,
Host: r.Host,
PostForm: r.PostForm,
RequestURI: r.RequestURI,
})
mutex.Unlock()
return r, nil
}

func main() {
proxy := goproxy.NewProxyHttpServer()
proxy.OnRequest(goproxy.ReqHostMatches(regexp.MustCompile("^.*$"))).
HandleConnect(goproxy.AlwaysMitm)
proxy.OnRequest().DoFunc(storeRequest)

requests = make(map[string]Request)

addr := flag.String("addr", ":8080", "proxy listen address")
flag.Parse()
log.Fatal(http.ListenAndServe(*addr, proxy))
}


I would like to know if this is a correct way of solving this problem.










share|improve this question
















bumped to the homepage by Community 2 days ago


This question has answers that may be good or bad; the system has marked it active so that they can be reviewed.



















    up vote
    5
    down vote

    favorite
    1












    Goproxy is a Go package implementing an HTTP proxy.
    I am using it to store requests from a client (eg: a web browser) for further processing.



    In an http.Request struct, the Body is an io.ReadCloser, it can only be read once.



    The problem I faced is that I need to read the Body to store it, but still make it accessible to goproxy so that it can be sent to the server.



    I solved it by reading the body with ioutil.ReadAll, and then creating a ReadCloser with the byte slice I got. I then assign this ReadCloser to the request Body.



    package main

    import (
    "bytes"
    "flag"
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
    "net/url"
    "regexp"
    "sync"

    "github.com/elazarl/goproxy"
    )

    var requests map[string]Request
    var mutex sync.Mutex

    type Request struct {
    Method string
    URL url.URL
    Proto string // "HTTP/1.0"
    ProtoMajor int // 1
    ProtoMinor int // 0
    Header http.Header
    Body byte
    ContentLength int64
    Host string
    PostForm url.Values
    RequestURI string
    }

    type RequestBody struct {
    *bytes.Reader
    }

    func (r RequestBody) Close() error {
    return nil
    }

    func storeRequest(r *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) {
    body, err := ioutil.ReadAll(r.Body)
    if err != nil {
    // only print error for now
    log.Println(err)
    return r, nil
    }
    r.Body.Close()
    r.Body = RequestBody{bytes.NewReader(body)}
    fmt.Println(string(body))
    mutex.Lock()
    requests[r.URL.Host] = append(requests[r.URL.Host], Request{
    Method: r.Method,
    URL: *r.URL,
    Proto: r.Proto,
    ProtoMajor: r.ProtoMajor,
    ProtoMinor: r.ProtoMinor,
    Header: r.Header,
    Body: body,
    ContentLength: r.ContentLength,
    Host: r.Host,
    PostForm: r.PostForm,
    RequestURI: r.RequestURI,
    })
    mutex.Unlock()
    return r, nil
    }

    func main() {
    proxy := goproxy.NewProxyHttpServer()
    proxy.OnRequest(goproxy.ReqHostMatches(regexp.MustCompile("^.*$"))).
    HandleConnect(goproxy.AlwaysMitm)
    proxy.OnRequest().DoFunc(storeRequest)

    requests = make(map[string]Request)

    addr := flag.String("addr", ":8080", "proxy listen address")
    flag.Parse()
    log.Fatal(http.ListenAndServe(*addr, proxy))
    }


    I would like to know if this is a correct way of solving this problem.










    share|improve this question
















    bumped to the homepage by Community 2 days ago


    This question has answers that may be good or bad; the system has marked it active so that they can be reviewed.

















      up vote
      5
      down vote

      favorite
      1









      up vote
      5
      down vote

      favorite
      1






      1





      Goproxy is a Go package implementing an HTTP proxy.
      I am using it to store requests from a client (eg: a web browser) for further processing.



      In an http.Request struct, the Body is an io.ReadCloser, it can only be read once.



      The problem I faced is that I need to read the Body to store it, but still make it accessible to goproxy so that it can be sent to the server.



      I solved it by reading the body with ioutil.ReadAll, and then creating a ReadCloser with the byte slice I got. I then assign this ReadCloser to the request Body.



      package main

      import (
      "bytes"
      "flag"
      "fmt"
      "io/ioutil"
      "log"
      "net/http"
      "net/url"
      "regexp"
      "sync"

      "github.com/elazarl/goproxy"
      )

      var requests map[string]Request
      var mutex sync.Mutex

      type Request struct {
      Method string
      URL url.URL
      Proto string // "HTTP/1.0"
      ProtoMajor int // 1
      ProtoMinor int // 0
      Header http.Header
      Body byte
      ContentLength int64
      Host string
      PostForm url.Values
      RequestURI string
      }

      type RequestBody struct {
      *bytes.Reader
      }

      func (r RequestBody) Close() error {
      return nil
      }

      func storeRequest(r *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) {
      body, err := ioutil.ReadAll(r.Body)
      if err != nil {
      // only print error for now
      log.Println(err)
      return r, nil
      }
      r.Body.Close()
      r.Body = RequestBody{bytes.NewReader(body)}
      fmt.Println(string(body))
      mutex.Lock()
      requests[r.URL.Host] = append(requests[r.URL.Host], Request{
      Method: r.Method,
      URL: *r.URL,
      Proto: r.Proto,
      ProtoMajor: r.ProtoMajor,
      ProtoMinor: r.ProtoMinor,
      Header: r.Header,
      Body: body,
      ContentLength: r.ContentLength,
      Host: r.Host,
      PostForm: r.PostForm,
      RequestURI: r.RequestURI,
      })
      mutex.Unlock()
      return r, nil
      }

      func main() {
      proxy := goproxy.NewProxyHttpServer()
      proxy.OnRequest(goproxy.ReqHostMatches(regexp.MustCompile("^.*$"))).
      HandleConnect(goproxy.AlwaysMitm)
      proxy.OnRequest().DoFunc(storeRequest)

      requests = make(map[string]Request)

      addr := flag.String("addr", ":8080", "proxy listen address")
      flag.Parse()
      log.Fatal(http.ListenAndServe(*addr, proxy))
      }


      I would like to know if this is a correct way of solving this problem.










      share|improve this question















      Goproxy is a Go package implementing an HTTP proxy.
      I am using it to store requests from a client (eg: a web browser) for further processing.



      In an http.Request struct, the Body is an io.ReadCloser, it can only be read once.



      The problem I faced is that I need to read the Body to store it, but still make it accessible to goproxy so that it can be sent to the server.



      I solved it by reading the body with ioutil.ReadAll, and then creating a ReadCloser with the byte slice I got. I then assign this ReadCloser to the request Body.



      package main

      import (
      "bytes"
      "flag"
      "fmt"
      "io/ioutil"
      "log"
      "net/http"
      "net/url"
      "regexp"
      "sync"

      "github.com/elazarl/goproxy"
      )

      var requests map[string]Request
      var mutex sync.Mutex

      type Request struct {
      Method string
      URL url.URL
      Proto string // "HTTP/1.0"
      ProtoMajor int // 1
      ProtoMinor int // 0
      Header http.Header
      Body byte
      ContentLength int64
      Host string
      PostForm url.Values
      RequestURI string
      }

      type RequestBody struct {
      *bytes.Reader
      }

      func (r RequestBody) Close() error {
      return nil
      }

      func storeRequest(r *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) {
      body, err := ioutil.ReadAll(r.Body)
      if err != nil {
      // only print error for now
      log.Println(err)
      return r, nil
      }
      r.Body.Close()
      r.Body = RequestBody{bytes.NewReader(body)}
      fmt.Println(string(body))
      mutex.Lock()
      requests[r.URL.Host] = append(requests[r.URL.Host], Request{
      Method: r.Method,
      URL: *r.URL,
      Proto: r.Proto,
      ProtoMajor: r.ProtoMajor,
      ProtoMinor: r.ProtoMinor,
      Header: r.Header,
      Body: body,
      ContentLength: r.ContentLength,
      Host: r.Host,
      PostForm: r.PostForm,
      RequestURI: r.RequestURI,
      })
      mutex.Unlock()
      return r, nil
      }

      func main() {
      proxy := goproxy.NewProxyHttpServer()
      proxy.OnRequest(goproxy.ReqHostMatches(regexp.MustCompile("^.*$"))).
      HandleConnect(goproxy.AlwaysMitm)
      proxy.OnRequest().DoFunc(storeRequest)

      requests = make(map[string]Request)

      addr := flag.String("addr", ":8080", "proxy listen address")
      flag.Parse()
      log.Fatal(http.ListenAndServe(*addr, proxy))
      }


      I would like to know if this is a correct way of solving this problem.







      http go






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 24 '16 at 18:02









      janos

      96.6k12122349




      96.6k12122349










      asked Nov 24 '16 at 15:11









      aguilbau

      261




      261





      bumped to the homepage by Community 2 days ago


      This question has answers that may be good or bad; the system has marked it active so that they can be reviewed.







      bumped to the homepage by Community 2 days ago


      This question has answers that may be good or bad; the system has marked it active so that they can be reviewed.
























          1 Answer
          1






          active

          oldest

          votes

















          up vote
          0
          down vote













          The hardest part of your question:




          Is it allowed to change Body field value of http.Request struct?




          Part of http.Request documentation:



          // Body is the request's body.
          //
          // For client requests a nil body means the request has no
          // body, such as a GET request. The HTTP Client's Transport
          // is responsible for calling the Close method.
          //
          // For server requests the Request Body is always non-nil
          // but will return EOF immediately when no body is present.
          // The Server will close the request body. The ServeHTTP
          // Handler does not need to.
          Body io.ReadCloser


          The documentation says nothing about it. So we need to find some top level policy on such things. As far as I know there is no one in Go documentation.



          Body field type is io.ReadCloser interface, the actual struct type is hidden behind it.




          • the actual type may have non exported fields which work in conjuction with Close method,

          • the hidden struct may be part of some reusable pool and will be lost,


          • HTTP trailer headers may be somewhere behind EOF.


          You may take a look at current net/http sources to find the answer, but it can change in next Go release.



          So I guess your best bet is to ask the Go community or even propose a change to Body documentation that will clear things out.





          Another approach would be to wrap original Body and read it together with request handler.






          share|improve this answer























            Your Answer





            StackExchange.ifUsing("editor", function () {
            return StackExchange.using("mathjaxEditing", function () {
            StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
            StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
            });
            });
            }, "mathjax-editing");

            StackExchange.ifUsing("editor", function () {
            StackExchange.using("externalEditor", function () {
            StackExchange.using("snippets", function () {
            StackExchange.snippets.init();
            });
            });
            }, "code-snippets");

            StackExchange.ready(function() {
            var channelOptions = {
            tags: "".split(" "),
            id: "196"
            };
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function() {
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled) {
            StackExchange.using("snippets", function() {
            createEditor();
            });
            }
            else {
            createEditor();
            }
            });

            function createEditor() {
            StackExchange.prepareEditor({
            heartbeatType: 'answer',
            convertImagesToLinks: false,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: null,
            bindNavPrevention: true,
            postfix: "",
            imageUploader: {
            brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
            contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
            allowUrls: true
            },
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            });


            }
            });














             

            draft saved


            draft discarded


















            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f148002%2freusing-body-in-http-requests-goproxy%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown

























            1 Answer
            1






            active

            oldest

            votes








            1 Answer
            1






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes








            up vote
            0
            down vote













            The hardest part of your question:




            Is it allowed to change Body field value of http.Request struct?




            Part of http.Request documentation:



            // Body is the request's body.
            //
            // For client requests a nil body means the request has no
            // body, such as a GET request. The HTTP Client's Transport
            // is responsible for calling the Close method.
            //
            // For server requests the Request Body is always non-nil
            // but will return EOF immediately when no body is present.
            // The Server will close the request body. The ServeHTTP
            // Handler does not need to.
            Body io.ReadCloser


            The documentation says nothing about it. So we need to find some top level policy on such things. As far as I know there is no one in Go documentation.



            Body field type is io.ReadCloser interface, the actual struct type is hidden behind it.




            • the actual type may have non exported fields which work in conjuction with Close method,

            • the hidden struct may be part of some reusable pool and will be lost,


            • HTTP trailer headers may be somewhere behind EOF.


            You may take a look at current net/http sources to find the answer, but it can change in next Go release.



            So I guess your best bet is to ask the Go community or even propose a change to Body documentation that will clear things out.





            Another approach would be to wrap original Body and read it together with request handler.






            share|improve this answer



























              up vote
              0
              down vote













              The hardest part of your question:




              Is it allowed to change Body field value of http.Request struct?




              Part of http.Request documentation:



              // Body is the request's body.
              //
              // For client requests a nil body means the request has no
              // body, such as a GET request. The HTTP Client's Transport
              // is responsible for calling the Close method.
              //
              // For server requests the Request Body is always non-nil
              // but will return EOF immediately when no body is present.
              // The Server will close the request body. The ServeHTTP
              // Handler does not need to.
              Body io.ReadCloser


              The documentation says nothing about it. So we need to find some top level policy on such things. As far as I know there is no one in Go documentation.



              Body field type is io.ReadCloser interface, the actual struct type is hidden behind it.




              • the actual type may have non exported fields which work in conjuction with Close method,

              • the hidden struct may be part of some reusable pool and will be lost,


              • HTTP trailer headers may be somewhere behind EOF.


              You may take a look at current net/http sources to find the answer, but it can change in next Go release.



              So I guess your best bet is to ask the Go community or even propose a change to Body documentation that will clear things out.





              Another approach would be to wrap original Body and read it together with request handler.






              share|improve this answer

























                up vote
                0
                down vote










                up vote
                0
                down vote









                The hardest part of your question:




                Is it allowed to change Body field value of http.Request struct?




                Part of http.Request documentation:



                // Body is the request's body.
                //
                // For client requests a nil body means the request has no
                // body, such as a GET request. The HTTP Client's Transport
                // is responsible for calling the Close method.
                //
                // For server requests the Request Body is always non-nil
                // but will return EOF immediately when no body is present.
                // The Server will close the request body. The ServeHTTP
                // Handler does not need to.
                Body io.ReadCloser


                The documentation says nothing about it. So we need to find some top level policy on such things. As far as I know there is no one in Go documentation.



                Body field type is io.ReadCloser interface, the actual struct type is hidden behind it.




                • the actual type may have non exported fields which work in conjuction with Close method,

                • the hidden struct may be part of some reusable pool and will be lost,


                • HTTP trailer headers may be somewhere behind EOF.


                You may take a look at current net/http sources to find the answer, but it can change in next Go release.



                So I guess your best bet is to ask the Go community or even propose a change to Body documentation that will clear things out.





                Another approach would be to wrap original Body and read it together with request handler.






                share|improve this answer














                The hardest part of your question:




                Is it allowed to change Body field value of http.Request struct?




                Part of http.Request documentation:



                // Body is the request's body.
                //
                // For client requests a nil body means the request has no
                // body, such as a GET request. The HTTP Client's Transport
                // is responsible for calling the Close method.
                //
                // For server requests the Request Body is always non-nil
                // but will return EOF immediately when no body is present.
                // The Server will close the request body. The ServeHTTP
                // Handler does not need to.
                Body io.ReadCloser


                The documentation says nothing about it. So we need to find some top level policy on such things. As far as I know there is no one in Go documentation.



                Body field type is io.ReadCloser interface, the actual struct type is hidden behind it.




                • the actual type may have non exported fields which work in conjuction with Close method,

                • the hidden struct may be part of some reusable pool and will be lost,


                • HTTP trailer headers may be somewhere behind EOF.


                You may take a look at current net/http sources to find the answer, but it can change in next Go release.



                So I guess your best bet is to ask the Go community or even propose a change to Body documentation that will clear things out.





                Another approach would be to wrap original Body and read it together with request handler.







                share|improve this answer














                share|improve this answer



                share|improve this answer








                edited Jun 27 at 19:56

























                answered Jun 27 at 10:15









                sineemore

                1,518524




                1,518524






























                     

                    draft saved


                    draft discarded



















































                     


                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function () {
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f148002%2freusing-body-in-http-requests-goproxy%23new-answer', 'question_page');
                    }
                    );

                    Post as a guest















                    Required, but never shown





















































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown

































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown







                    Popular posts from this blog

                    Quarter-circle Tiles

                    build a pushdown automaton that recognizes the reverse language of a given pushdown automaton?

                    Mont Emei