|
@@ -25,7 +25,6 @@ import (
|
|
|
"errors"
|
|
"errors"
|
|
|
"fmt"
|
|
"fmt"
|
|
|
"io/ioutil"
|
|
"io/ioutil"
|
|
|
- "net"
|
|
|
|
|
"net/http"
|
|
"net/http"
|
|
|
"strconv"
|
|
"strconv"
|
|
|
)
|
|
)
|
|
@@ -38,6 +37,7 @@ type Session struct {
|
|
|
sessionId string
|
|
sessionId string
|
|
|
config *Config
|
|
config *Config
|
|
|
tunnel *Tunnel
|
|
tunnel *Tunnel
|
|
|
|
|
+ pendingConns *PendingConns
|
|
|
psiphonHttpsClient *http.Client
|
|
psiphonHttpsClient *http.Client
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -50,7 +50,8 @@ func NewSession(
|
|
|
tunnel *Tunnel,
|
|
tunnel *Tunnel,
|
|
|
localHttpProxyAddress, sessionId string) (session *Session, err error) {
|
|
localHttpProxyAddress, sessionId string) (session *Session, err error) {
|
|
|
|
|
|
|
|
- psiphonHttpsClient, err := makePsiphonHttpsClient(tunnel, localHttpProxyAddress)
|
|
|
|
|
|
|
+ pendingConns := new(PendingConns)
|
|
|
|
|
+ psiphonHttpsClient, err := makePsiphonHttpsClient(tunnel, pendingConns, localHttpProxyAddress)
|
|
|
if err != nil {
|
|
if err != nil {
|
|
|
return nil, ContextError(err)
|
|
return nil, ContextError(err)
|
|
|
}
|
|
}
|
|
@@ -58,6 +59,7 @@ func NewSession(
|
|
|
sessionId: sessionId,
|
|
sessionId: sessionId,
|
|
|
config: config,
|
|
config: config,
|
|
|
tunnel: tunnel,
|
|
tunnel: tunnel,
|
|
|
|
|
+ pendingConns: pendingConns,
|
|
|
psiphonHttpsClient: psiphonHttpsClient,
|
|
psiphonHttpsClient: psiphonHttpsClient,
|
|
|
}
|
|
}
|
|
|
// Sending two seperate requests is a legacy from when the handshake was
|
|
// Sending two seperate requests is a legacy from when the handshake was
|
|
@@ -257,14 +259,27 @@ func (session *Session) doGetRequest(requestUrl string) (responseBody []byte, er
|
|
|
// As the custom dialer makes an explicit TLS connection, URLs submitted to the returned
|
|
// As the custom dialer makes an explicit TLS connection, URLs submitted to the returned
|
|
|
// http.Client should use the "http://" scheme. Otherwise http.Transport will try to do another TLS
|
|
// http.Client should use the "http://" scheme. Otherwise http.Transport will try to do another TLS
|
|
|
// handshake inside the explicit TLS session.
|
|
// handshake inside the explicit TLS session.
|
|
|
-func makePsiphonHttpsClient(tunnel *Tunnel, localHttpProxyAddress string) (httpsClient *http.Client, err error) {
|
|
|
|
|
|
|
+func makePsiphonHttpsClient(
|
|
|
|
|
+ tunnel *Tunnel,
|
|
|
|
|
+ pendingConns *PendingConns,
|
|
|
|
|
+ localHttpProxyAddress string) (httpsClient *http.Client, err error) {
|
|
|
|
|
+
|
|
|
certificate, err := DecodeCertificate(tunnel.serverEntry.WebServerCertificate)
|
|
certificate, err := DecodeCertificate(tunnel.serverEntry.WebServerCertificate)
|
|
|
if err != nil {
|
|
if err != nil {
|
|
|
return nil, ContextError(err)
|
|
return nil, ContextError(err)
|
|
|
}
|
|
}
|
|
|
|
|
+ // Note: This use of readTimeout will tear down persistent HTTP connections, which is not the
|
|
|
|
|
+ // intended purpose. The readTimeout is to abort NewSession when the Psiphon server responds to
|
|
|
|
|
+ // handshake/connected requests but fails to deliver the response body (e.g., ResponseHeaderTimeout
|
|
|
|
|
+ // is not sufficient to timeout this case).
|
|
|
|
|
+ directDialer := NewDirectDialer(
|
|
|
|
|
+ PSIPHON_API_SERVER_TIMEOUT,
|
|
|
|
|
+ PSIPHON_API_SERVER_TIMEOUT,
|
|
|
|
|
+ PSIPHON_API_SERVER_TIMEOUT,
|
|
|
|
|
+ pendingConns)
|
|
|
dialer := NewCustomTLSDialer(
|
|
dialer := NewCustomTLSDialer(
|
|
|
&CustomTLSConfig{
|
|
&CustomTLSConfig{
|
|
|
- Dial: new(net.Dialer).Dial,
|
|
|
|
|
|
|
+ Dial: directDialer,
|
|
|
Timeout: PSIPHON_API_SERVER_TIMEOUT,
|
|
Timeout: PSIPHON_API_SERVER_TIMEOUT,
|
|
|
HttpProxyAddress: localHttpProxyAddress,
|
|
HttpProxyAddress: localHttpProxyAddress,
|
|
|
SendServerName: false,
|
|
SendServerName: false,
|