@@ -3,8 +3,10 @@ package handler
33import  (
44	"encoding/json" 
55	"io/ioutil" 
6+ 	"mime/multipart" 
67	"net/http" 
78	"net/url" 
9+ 	"strconv" 
810	"strings" 
911
1012	"github.com/graphql-go/graphql" 
@@ -13,17 +15,24 @@ import (
1315)
1416
1517const  (
16- 	ContentTypeJSON            =  "application/json" 
17- 	ContentTypeGraphQL         =  "application/graphql" 
18- 	ContentTypeFormURLEncoded  =  "application/x-www-form-urlencoded" 
18+ 	ContentTypeJSON               =  "application/json" 
19+ 	ContentTypeGraphQL            =  "application/graphql" 
20+ 	ContentTypeFormURLEncoded     =  "application/x-www-form-urlencoded" 
21+ 	ContentTypeMultipartFormData  =  "multipart/form-data" 
1922)
2023
24+ type  MultipartFile  struct  {
25+ 	File    multipart.File 
26+ 	Header  * multipart.FileHeader 
27+ }
28+ 
2129type  Handler  struct  {
2230	Schema        * graphql.Schema 
2331	pretty        bool 
2432	graphiql      bool 
2533	playground    bool 
2634	rootObjectFn  RootObjectFn 
35+ 	maxMemory     int64 
2736}
2837type  RequestOptions  struct  {
2938	Query          string                  `json:"query" url:"query" schema:"query"` 
@@ -57,7 +66,7 @@ func getFromForm(values url.Values) *RequestOptions {
5766}
5867
5968// RequestOptions Parses a http.Request into GraphQL request options struct 
60- func  NewRequestOptions (r  * http.Request ) * RequestOptions  {
69+ func  NewRequestOptions (r  * http.Request ,  maxMemory   int64 ) * RequestOptions  {
6170	if  reqOpt  :=  getFromForm (r .URL .Query ()); reqOpt  !=  nil  {
6271		return  reqOpt 
6372	}
@@ -95,6 +104,89 @@ func NewRequestOptions(r *http.Request) *RequestOptions {
95104
96105		return  & RequestOptions {}
97106
107+ 	case  ContentTypeMultipartFormData :
108+ 		if  err  :=  r .ParseMultipartForm (maxMemory ); err  !=  nil  {
109+ 			// fmt.Printf("Parse Multipart Failed %v", err) 
110+ 			return  & RequestOptions {}
111+ 		}
112+ 
113+ 		// @TODO handle array case... 
114+ 
115+ 		operationsParam  :=  r .FormValue ("operations" )
116+ 		var  opts  RequestOptions 
117+ 		if  err  :=  json .Unmarshal ([]byte (operationsParam ), & opts ); err  !=  nil  {
118+ 			// fmt.Printf("Parse Operations Failed %v", err) 
119+ 			return  & RequestOptions {}
120+ 		}
121+ 
122+ 		mapParam  :=  r .FormValue ("map" )
123+ 		mapValues  :=  make (map [string ]([]string ))
124+ 		if  len (mapParam ) !=  0  {
125+ 			if  err  :=  json .Unmarshal ([]byte (mapParam ), & mapValues ); err  !=  nil  {
126+ 				// fmt.Printf("Parse map Failed %v", err) 
127+ 				return  & RequestOptions {}
128+ 			}
129+ 		}
130+ 
131+ 		variables  :=  opts 
132+ 
133+ 		for  key , value  :=  range  mapValues  {
134+ 			for  _ , v  :=  range  value  {
135+ 				if  file , header , err  :=  r .FormFile (key ); err  ==  nil  {
136+ 
137+ 					// Now set the path in ther variables 
138+ 					var  node  interface {} =  variables 
139+ 
140+ 					parts  :=  strings .Split (v , "." )
141+ 					last  :=  parts [len (parts )- 1 ]
142+ 
143+ 					for  _ , vv  :=  range  parts [:len (parts )- 1 ] {
144+ 						// fmt.Printf("Doing vv=%s type=%T parts=%v\n", vv, node, parts) 
145+ 						switch  node .(type ) {
146+ 						case  RequestOptions :
147+ 							if  vv  ==  "variables"  {
148+ 								node  =  opts .Variables 
149+ 							} else  {
150+ 								// panic("Invalid top level tag") 
151+ 								return  & RequestOptions {}
152+ 							}
153+ 						case  map [string ]interface {}:
154+ 							node  =  node .(map [string ]interface {})[vv ]
155+ 						case  []interface {}:
156+ 							if  idx , err  :=  strconv .ParseInt (vv , 10 , 64 ); err  ==  nil  {
157+ 								node  =  node .([]interface {})[idx ]
158+ 							} else  {
159+ 								// panic("Unable to lookup index") 
160+ 								return  & RequestOptions {}
161+ 							}
162+ 						default :
163+ 							// panic(fmt.Errorf("Unknown type %T", node)) 
164+ 							return  & RequestOptions {}
165+ 						}
166+ 					}
167+ 
168+ 					data  :=  & MultipartFile {File : file , Header : header }
169+ 
170+ 					switch  node .(type ) {
171+ 					case  map [string ]interface {}:
172+ 						node .(map [string ]interface {})[last ] =  data 
173+ 					case  []interface {}:
174+ 						if  idx , err  :=  strconv .ParseInt (last , 10 , 64 ); err  ==  nil  {
175+ 							node .([]interface {})[idx ] =  data 
176+ 						} else  {
177+ 							// panic("Unable to lookup index") 
178+ 							return  & RequestOptions {}
179+ 						}
180+ 					default :
181+ 						// panic(fmt.Errorf("Unknown last type %T", node)) 
182+ 						return  & RequestOptions {}
183+ 					}
184+ 				}
185+ 			}
186+ 		}
187+ 
188+ 		return  & opts 
189+ 
98190	case  ContentTypeJSON :
99191		fallthrough 
100192	default :
@@ -119,7 +211,7 @@ func NewRequestOptions(r *http.Request) *RequestOptions {
119211// user-provided context. 
120212func  (h  * Handler ) ContextHandler (ctx  context.Context , w  http.ResponseWriter , r  * http.Request ) {
121213	// get query 
122- 	opts  :=  NewRequestOptions (r )
214+ 	opts  :=  NewRequestOptions (r ,  h . maxMemory )
123215
124216	// execute graphql query 
125217	params  :=  graphql.Params {
@@ -182,14 +274,15 @@ type Config struct {
182274	GraphiQL      bool 
183275	Playground    bool 
184276	RootObjectFn  RootObjectFn 
277+ 	MaxMemory     int64 
185278}
186279
187280func  NewConfig () * Config  {
188281	return  & Config {
189- 		Schema :      nil ,
190- 		Pretty :      true ,
191- 		GraphiQL :    true ,
192- 		Playground :  false ,
282+ 		Schema :    nil ,
283+ 		Pretty :    true ,
284+ 		GraphiQL :  true ,
285+ 		MaxMemory :  0 ,
193286	}
194287}
195288
@@ -201,11 +294,17 @@ func New(p *Config) *Handler {
201294		panic ("undefined GraphQL schema" )
202295	}
203296
297+ 	maxMemory  :=  p .MaxMemory 
298+ 	if  maxMemory  ==  0  {
299+ 		maxMemory  =  32  <<  20  // 32MB 
300+ 	}
301+ 
204302	return  & Handler {
205303		Schema :       p .Schema ,
206304		pretty :       p .Pretty ,
207305		graphiql :     p .GraphiQL ,
208306		playground :   p .Playground ,
209307		rootObjectFn : p .RootObjectFn ,
308+ 		maxMemory :    maxMemory ,
210309	}
211310}
0 commit comments