@@ -6,9 +6,14 @@ package soup
66
77import (
88 "bytes"
9+ "encoding/json"
910 "fmt"
11+ "io"
1012 "io/ioutil"
1113 "net/http"
14+ "net/http/httputil"
15+ "net/url"
16+ netURL "net/url"
1217 "regexp"
1318 "strings"
1419
@@ -35,6 +40,10 @@ const (
3540 ErrCreatingGetRequest
3641 // ErrInGetRequest will be returned when there was an error during the get request
3742 ErrInGetRequest
43+ // ErrCreatingPostRequest will be returned when the post request couldn't be created
44+ ErrCreatingPostRequest
45+ // ErrMarshallingPostRequest will be returned when the body of a post request couldn't be serialized
46+ ErrMarshallingPostRequest
3847 // ErrReadingResponse will be returned if there was an error reading the response to our get request
3948 ErrReadingResponse
4049)
@@ -99,10 +108,34 @@ func GetWithClient(url string, client *http.Client) (string, error) {
99108 req , err := http .NewRequest ("GET" , url , nil )
100109 if err != nil {
101110 if debug {
102- panic ("Couldn't perform GET request to " + url )
111+ panic ("Couldn't create GET request to " + url )
103112 }
104113 return "" , newError (ErrCreatingGetRequest , "error creating get request to " + url )
105114 }
115+
116+ setHeadersAndCookies (req )
117+
118+ // Perform request
119+ resp , err := client .Do (req )
120+ if err != nil {
121+ if debug {
122+ panic ("Couldn't perform GET request to " + url )
123+ }
124+ return "" , newError (ErrInGetRequest , "couldn't perform GET request to " + url )
125+ }
126+ defer resp .Body .Close ()
127+ bytes , err := ioutil .ReadAll (resp .Body )
128+ if err != nil {
129+ if debug {
130+ panic ("Unable to read the response body" )
131+ }
132+ return "" , newError (ErrReadingResponse , "unable to read the response body" )
133+ }
134+ return string (bytes ), nil
135+ }
136+
137+ // setHeadersAndCookies helps build a request
138+ func setHeadersAndCookies (req * http.Request ) {
106139 // Set headers
107140 for hName , hValue := range Headers {
108141 req .Header .Set (hName , hValue )
@@ -114,13 +147,66 @@ func GetWithClient(url string, client *http.Client) (string, error) {
114147 Value : cValue ,
115148 })
116149 }
150+ }
151+
152+ // getBodyReader serializes the body for a network request. See the test file for examples
153+ func getBodyReader (rawBody interface {}) (io.Reader , error ) {
154+ var bodyReader io.Reader
155+
156+ if rawBody != nil {
157+ switch body := rawBody .(type ) {
158+ case map [string ]string :
159+ jsonBody , err := json .Marshal (body )
160+ if err != nil {
161+ if debug {
162+ panic ("Unable to read the response body" )
163+ }
164+ return nil , newError (ErrMarshallingPostRequest , "couldn't serialize map of strings to JSON." )
165+ }
166+ bodyReader = bytes .NewBuffer (jsonBody )
167+ case netURL.Values :
168+ bodyReader = strings .NewReader (body .Encode ())
169+ case []byte : //expects JSON format
170+ bodyReader = bytes .NewBuffer (body )
171+ case string : //expects JSON format
172+ bodyReader = strings .NewReader (body )
173+ default :
174+ return nil , newError (ErrMarshallingPostRequest , fmt .Sprintf ("Cannot handle body type %T" , rawBody ))
175+ }
176+ }
177+
178+ return bodyReader , nil
179+ }
180+
181+ // PostWithClient returns the HTML returned by the url using a provided HTTP client
182+ // The type of the body must conform to one of the types listed in func getBodyReader()
183+ func PostWithClient (url string , bodyType string , body interface {}, client * http.Client ) (string , error ) {
184+ bodyReader , err := getBodyReader (body )
185+ if err != nil {
186+ return "todo:" , err
187+ }
188+
189+ req , err := http .NewRequest ("POST" , url , bodyReader )
190+ Header ("Content-Type" , bodyType )
191+ setHeadersAndCookies (req )
192+
193+ if debug {
194+ // Save a copy of this request for debugging.
195+ requestDump , err := httputil .DumpRequest (req , true )
196+ if err != nil {
197+ fmt .Println (err )
198+ }
199+ fmt .Println (string (requestDump ))
200+ }
201+
117202 // Perform request
118203 resp , err := client .Do (req )
204+
119205 if err != nil {
120206 if debug {
121- panic ("Couldn't perform GET request to " + url )
207+ panic ("Couldn't perform POST request to " + url )
122208 }
123- return "" , newError (ErrInGetRequest , "couldn't perform GET request to " + url )
209+ return "" , newError (ErrCreatingPostRequest , "couldn't perform POST request to" + url )
124210 }
125211 defer resp .Body .Close ()
126212 bytes , err := ioutil .ReadAll (resp .Body )
@@ -133,7 +219,17 @@ func GetWithClient(url string, client *http.Client) (string, error) {
133219 return string (bytes ), nil
134220}
135221
136- // Get returns the HTML returned by the url in string using the default HTTP client
222+ // Post returns the HTML returned by the url as a string using the default HTTP client
223+ func Post (url string , bodyType string , body interface {}) (string , error ) {
224+ return PostWithClient (url , bodyType , body , defaultClient )
225+ }
226+
227+ // PostForm is a convenience method for POST requests that
228+ func PostForm (url string , data url.Values ) (string , error ) {
229+ return PostWithClient (url , "application/x-www-form-urlencoded" , data , defaultClient )
230+ }
231+
232+ // Get returns the HTML returned by the url as a string using the default HTTP client
137233func Get (url string ) (string , error ) {
138234 return GetWithClient (url , defaultClient )
139235}
0 commit comments