@@ -2,6 +2,7 @@ package http
22
33import (
44 "crypto/tls"
5+ "crypto/x509"
56 "encoding/json"
67 "log"
78 "net/http"
@@ -81,22 +82,24 @@ func checkClient(L *lua.LState) *LuaClient {
8182
8283// http.client(config) returns (user data, error)
8384// config table:
84- // {
85- // proxy="http(s)://<user>:<password>@host:<port>",
86- // timeout= 10,
87- // insecure_ssl=false,
88- // user_agent = "gopher-lua",
89- // basic_auth_user = "",
90- // basic_auth_password = "",
91- // headers = {"key"="value"},
92- // debug = false,
93- // }
85+ //
86+ // {
87+ // proxy="http(s)://<user>:<password>@host:<port>",
88+ // timeout= 10,
89+ // insecure_ssl=false,
90+ // user_agent = "gopher-lua",
91+ // basic_auth_user = "",
92+ // basic_auth_password = "",
93+ // headers = {"key"="value"},
94+ // debug = false,
95+ // }
9496func New (L * lua.LState ) int {
9597 var config * lua.LTable
9698 if L .GetTop () > 0 {
9799 config = L .CheckTable (1 )
98100 }
99101 client := & LuaClient {Client : & http.Client {Timeout : DefaultTimeout }, userAgent : DefaultUserAgent }
102+ tlsConfig := & tls.Config {}
100103 transport := & http.Transport {}
101104 // parse env
102105 if proxyEnv := os .Getenv (`HTTP_PROXY` ); proxyEnv != `` {
@@ -110,17 +113,35 @@ func New(L *lua.LState) int {
110113 transport .IdleConnTimeout = DefaultTimeout
111114 // parse config
112115 if config != nil {
116+ // Client Cert and Key go together and handling in loop is challenging - just pull them out here
117+ clientPublicCertPEMFile := L .GetField (config , `client_public_cert_pem_file` )
118+ clientPrivateKeyPemFile := L .GetField (config , `client_private_key_pem_file` )
119+ if clientPublicCertPEMFile != lua .LNil && clientPrivateKeyPemFile != lua .LNil {
120+ if _ , ok := clientPublicCertPEMFile .(lua.LString ); ! ok {
121+ L .ArgError (1 , "client_public_cert_pem_file must be string" )
122+ }
123+ if _ , ok := clientPrivateKeyPemFile .(lua.LString ); ! ok {
124+ L .ArgError (1 , "client_private_key_pem_file must be string" )
125+ }
126+ clientCert , err := tls .LoadX509KeyPair (clientPublicCertPEMFile .String (), clientPrivateKeyPemFile .String ())
127+ if err != nil {
128+ L .RaiseError ("error loading client certificate from %s and %s: %v" ,
129+ clientPublicCertPEMFile , clientPrivateKeyPemFile , err )
130+ }
131+ tlsConfig .Certificates = []tls.Certificate {clientCert }
132+ transport .TLSClientConfig = tlsConfig
133+ }
113134 config .ForEach (func (k lua.LValue , v lua.LValue ) {
135+ switch k .String () {
114136 // parse timeout
115- if k . String () == `timeout` {
137+ case `timeout` :
116138 if value , ok := v .(lua.LNumber ); ok {
117139 client .Timeout = time .Duration (value ) * time .Second
118140 } else {
119141 L .ArgError (1 , "timeout must be number" )
120142 }
121- }
122143 // parse proxy
123- if k . String () == `proxy` {
144+ case `proxy` :
124145 if value , ok := v .(lua.LString ); ok {
125146 proxyUrl , err := url .Parse (value .String ())
126147 if err == nil {
@@ -131,51 +152,59 @@ func New(L *lua.LState) int {
131152 } else {
132153 L .ArgError (1 , "http_proxy must be string" )
133154 }
134- }
135155 // parse insecure_ssl
136- if k . String () == `insecure_ssl` {
156+ case `insecure_ssl` :
137157 if value , ok := v .(lua.LBool ); ok {
138- transport .TLSClientConfig = & tls.Config {InsecureSkipVerify : bool (value )}
158+ tlsConfig .InsecureSkipVerify = bool (value )
159+ transport .TLSClientConfig = tlsConfig
139160 } else {
140161 L .ArgError (1 , "insecure_ssl must be bool" )
141162 }
142- }
163+ // parse root_cas
164+ case `root_cas_pem_file` :
165+ if value , ok := v .(lua.LString ); ok {
166+ pemData , err := os .ReadFile (string (value ))
167+ if err != nil {
168+ L .RaiseError ("error loading root_cas_pem_file from %s: %v" , value , err )
169+ }
170+ tlsConfig .RootCAs = x509 .NewCertPool ()
171+ tlsConfig .RootCAs .AppendCertsFromPEM (pemData )
172+ transport .TLSClientConfig = tlsConfig
173+ } else {
174+ L .ArgError (1 , "root_cas_pem_file must be string" )
175+ }
143176 // parse user_agent
144- if k . String () == `user_agent` {
177+ case `user_agent` :
145178 if _ , ok := v .(lua.LString ); ok {
146179 client .userAgent = v .String ()
147180 } else {
148181 L .ArgError (1 , "user_agent must be string" )
149182 }
150- }
151183 // parse basic_auth_user
152- if k . String () == `basic_auth_user` {
184+ case `basic_auth_user` :
153185 if _ , ok := v .(lua.LString ); ok {
154186 user := v .String ()
155187 client .basicAuthUser = & user
156188 } else {
157189 L .ArgError (1 , "basic_auth_user must be string" )
158190 }
159- }
160191 // parse basic_auth_password
161- if k . String () == `basic_auth_password` {
192+ case `basic_auth_password` :
162193 if _ , ok := v .(lua.LString ); ok {
163194 password := v .String ()
164195 client .basicAuthPasswd = & password
165196 } else {
166197 L .ArgError (1 , "basic_auth_password must be string" )
167198 }
168- }
169199 // parse debug
170- if k . String () == `debug` {
200+ case `debug` :
171201 if value , ok := v .(lua.LBool ); ok {
172202 client .debug = bool (value )
173203 } else {
174204 L .ArgError (1 , "debug must be bool" )
175205 }
176- }
177206 // parse headers
178- if k . String () == `headers` {
207+ case `headers` :
179208 if tbl , ok := v .(* lua.LTable ); ok {
180209 headers := make (map [string ]string , 0 )
181210 data , err := lua_json .ValueEncode (tbl )
0 commit comments