支持设置代理,包括http/socks5

main
orestonce 2022-06-21 07:22:53 +08:00
parent 4705133ce7
commit 199fd9b9fc
10 changed files with 248 additions and 82 deletions

View File

@ -22,7 +22,7 @@
* [x] windows、linux、mac都支持ffmpeg合并ts列表为mp4
* [x] 充分测试后,使用 https://github.com/yapingcat/gomedia 代替ffmpeg进行格式转换
* [x] 支持嵌套m3u8的url
* [ ] 支持设置代理
* [x] 支持设置代理
* [ ] 支持从curl命令解析出需要的header、auth-basic、cookie等信息正如 https://github.com/cxjava/m3u8-downloader 一样
## 二次开发操作手册:
* 如果只开发命令行版本, 则只需要修改*.go文件, 然后编译 cmd/main.go 即可

View File

@ -33,6 +33,7 @@ func init() {
rootCmd.Flags().StringVarP(&gRunReq.SaveDir, "SaveDir", "d", "", "文件保存路径(默认为当前路径)")
rootCmd.Flags().StringVarP(&gRunReq.FileName, "FileName", "f", "", "文件名")
rootCmd.Flags().IntVarP(&gRunReq.SkipTsCountFromHead, "SkipTsCountFromHead", "", 0, "跳过前面几个ts")
rootCmd.Flags().StringVarP(&gRunReq.SetProxy, "SetProxy", "", "", "代理设置, http://127.0.0.1:8080, socks")
}
func main() {

View File

@ -69,6 +69,7 @@ type RunDownload_Req struct {
SaveDir string // "文件保存路径(默认为当前路径)"
FileName string // 文件名
SkipTsCountFromHead int // 跳过前面几个ts
SetProxy string
}
type downloadEnv struct {
@ -246,12 +247,14 @@ var gOldEnv *downloadEnv
var gOldEnvLocker sync.Mutex
func RunDownload(req RunDownload_Req) (resp RunDownload_Resp) {
req.SetProxy = strings.ToLower(req.SetProxy)
env := &downloadEnv{
client: &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: req.Insecure,
},
DialContext: newDialContext(req.SetProxy),
},
Timeout: time.Second * 10,
},
@ -577,7 +580,7 @@ func (this *downloadEnv) doGetRequest(urlS string) (data []byte, err error) {
}
req = req.WithContext(this.ctx)
req.Header = this.header
resp, err := http.DefaultClient.Do(req)
resp, err := this.client.Do(req)
if err != nil {
return nil, err
}

4
go.mod
View File

@ -3,11 +3,13 @@ module m3u8d
go 1.17
require (
github.com/elazarl/goproxy v0.0.0-20220529153421-8ea89ba92021
github.com/orestonce/cdb v0.0.0-20220528005855-d187c22240e2
github.com/orestonce/go2cpp v0.0.0-20220507123906-b66d3600c123
github.com/orestonce/go2cpp v0.0.0-20220605110533-c77a8dd7fdfd
github.com/orestonce/gopool v0.0.0-20220508090328-d7d56d45b171
github.com/spf13/cobra v1.4.0
github.com/yapingcat/gomedia v0.0.0-20220619163023-5a5544262ef6
golang.org/x/net v0.0.0-20220617184016-355a448f1bc9
)
require (

16
go.sum
View File

@ -1,12 +1,17 @@
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/elazarl/goproxy v0.0.0-20220529153421-8ea89ba92021 h1:EbF0UihnxWRcIMOwoVtqnAylsqcjzqpSvMdjF2Ud4rA=
github.com/elazarl/goproxy v0.0.0-20220529153421-8ea89ba92021/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2 h1:dWB6v3RcOy03t/bUadywsbyrQwCqZeNIEX6M1OtSZOM=
github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/orestonce/cdb v0.0.0-20220528005855-d187c22240e2 h1:AmGkuxSIOW0gA/jetY8d1DVV0cyQ08FMCxa1arkI6HQ=
github.com/orestonce/cdb v0.0.0-20220528005855-d187c22240e2/go.mod h1:HMNNdA1LMQFJRwobtCzVevWcInFSo9rfs1fYeVYwU+c=
github.com/orestonce/go2cpp v0.0.0-20220507123906-b66d3600c123 h1:AyAKqO7kC68OKiZk9GV4bUG+xMe1VQCy2CPbS9hvdY4=
github.com/orestonce/go2cpp v0.0.0-20220507123906-b66d3600c123/go.mod h1:1fsOAZftk08/dOTRqlp6f/MVwaEKOhrnPUg0RtWiSdY=
github.com/orestonce/go2cpp v0.0.0-20220605110533-c77a8dd7fdfd h1:q4MMzJG2Zdh9OLSiQfhPqL0/GGQ+B+SZmYDjbOjGW7Y=
github.com/orestonce/go2cpp v0.0.0-20220605110533-c77a8dd7fdfd/go.mod h1:1fsOAZftk08/dOTRqlp6f/MVwaEKOhrnPUg0RtWiSdY=
github.com/orestonce/gopool v0.0.0-20220508090328-d7d56d45b171 h1:NnOl6HTrhrlTT7aaAybVOtq+fEztGFMoQtegckgwLdk=
github.com/orestonce/gopool v0.0.0-20220508090328-d7d56d45b171/go.mod h1:MCQUrAPiG9/PTjHJuGqWLasKbIaG6z62KO6kfp90byM=
github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/spf13/cobra v1.4.0 h1:y+wJpx64xcgO1V+RcnwW0LEHxTKRi2ZDPSBjWnrg88Q=
github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g=
@ -14,5 +19,12 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/yapingcat/gomedia v0.0.0-20220619163023-5a5544262ef6 h1:d9MplS5tlYkVzS20zFz47Hg82wvTnTk4Oafwo6j9Eb0=
github.com/yapingcat/gomedia v0.0.0-20220619163023-5a5544262ef6/go.mod h1:WSZ59bidJOO40JSJmLqlkBJrjZCtjbKKkygEMfzY/kc=
golang.org/x/net v0.0.0-20220617184016-355a448f1bc9 h1:Yqz/iviulwKwAREEeUd3nbBFn0XuyJqkoft2IlrvOhc=
golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=

View File

@ -83,53 +83,63 @@ RunDownload_Resp RunDownload(RunDownload_Req in0){
std::string in;
{
{
uint32_t tmp19 = in0.M3u8Url.length();
char tmp20[4];
tmp20[0] = (uint32_t(tmp19) >> 24) & 0xFF;
tmp20[1] = (uint32_t(tmp19) >> 16) & 0xFF;
tmp20[2] = (uint32_t(tmp19) >> 8) & 0xFF;
tmp20[3] = (uint32_t(tmp19) >> 0) & 0xFF;
in.append(tmp20, 4);
uint32_t tmp22 = in0.M3u8Url.length();
char tmp23[4];
tmp23[0] = (uint32_t(tmp22) >> 24) & 0xFF;
tmp23[1] = (uint32_t(tmp22) >> 16) & 0xFF;
tmp23[2] = (uint32_t(tmp22) >> 8) & 0xFF;
tmp23[3] = (uint32_t(tmp22) >> 0) & 0xFF;
in.append(tmp23, 4);
in.append(in0.M3u8Url);
}
{
uint32_t tmp21 = in0.HostType.length();
char tmp22[4];
tmp22[0] = (uint32_t(tmp21) >> 24) & 0xFF;
tmp22[1] = (uint32_t(tmp21) >> 16) & 0xFF;
tmp22[2] = (uint32_t(tmp21) >> 8) & 0xFF;
tmp22[3] = (uint32_t(tmp21) >> 0) & 0xFF;
in.append(tmp22, 4);
uint32_t tmp24 = in0.HostType.length();
char tmp25[4];
tmp25[0] = (uint32_t(tmp24) >> 24) & 0xFF;
tmp25[1] = (uint32_t(tmp24) >> 16) & 0xFF;
tmp25[2] = (uint32_t(tmp24) >> 8) & 0xFF;
tmp25[3] = (uint32_t(tmp24) >> 0) & 0xFF;
in.append(tmp25, 4);
in.append(in0.HostType);
}
in.append((char*)(&in0.Insecure), 1);
{
uint32_t tmp23 = in0.SaveDir.length();
char tmp24[4];
tmp24[0] = (uint32_t(tmp23) >> 24) & 0xFF;
tmp24[1] = (uint32_t(tmp23) >> 16) & 0xFF;
tmp24[2] = (uint32_t(tmp23) >> 8) & 0xFF;
tmp24[3] = (uint32_t(tmp23) >> 0) & 0xFF;
in.append(tmp24, 4);
uint32_t tmp26 = in0.SaveDir.length();
char tmp27[4];
tmp27[0] = (uint32_t(tmp26) >> 24) & 0xFF;
tmp27[1] = (uint32_t(tmp26) >> 16) & 0xFF;
tmp27[2] = (uint32_t(tmp26) >> 8) & 0xFF;
tmp27[3] = (uint32_t(tmp26) >> 0) & 0xFF;
in.append(tmp27, 4);
in.append(in0.SaveDir);
}
{
uint32_t tmp25 = in0.FileName.length();
char tmp26[4];
tmp26[0] = (uint32_t(tmp25) >> 24) & 0xFF;
tmp26[1] = (uint32_t(tmp25) >> 16) & 0xFF;
tmp26[2] = (uint32_t(tmp25) >> 8) & 0xFF;
tmp26[3] = (uint32_t(tmp25) >> 0) & 0xFF;
in.append(tmp26, 4);
uint32_t tmp28 = in0.FileName.length();
char tmp29[4];
tmp29[0] = (uint32_t(tmp28) >> 24) & 0xFF;
tmp29[1] = (uint32_t(tmp28) >> 16) & 0xFF;
tmp29[2] = (uint32_t(tmp28) >> 8) & 0xFF;
tmp29[3] = (uint32_t(tmp28) >> 0) & 0xFF;
in.append(tmp29, 4);
in.append(in0.FileName);
}
{
char tmp27[4];
tmp27[0] = (uint32_t(in0.SkipTsCountFromHead) >> 24) & 0xFF;
tmp27[1] = (uint32_t(in0.SkipTsCountFromHead) >> 16) & 0xFF;
tmp27[2] = (uint32_t(in0.SkipTsCountFromHead) >> 8) & 0xFF;
tmp27[3] = (uint32_t(in0.SkipTsCountFromHead) >> 0) & 0xFF;
in.append(tmp27, 4);
char tmp30[4];
tmp30[0] = (uint32_t(in0.SkipTsCountFromHead) >> 24) & 0xFF;
tmp30[1] = (uint32_t(in0.SkipTsCountFromHead) >> 16) & 0xFF;
tmp30[2] = (uint32_t(in0.SkipTsCountFromHead) >> 8) & 0xFF;
tmp30[3] = (uint32_t(in0.SkipTsCountFromHead) >> 0) & 0xFF;
in.append(tmp30, 4);
}
{
uint32_t tmp31 = in0.SetProxy.length();
char tmp32[4];
tmp32[0] = (uint32_t(tmp31) >> 24) & 0xFF;
tmp32[1] = (uint32_t(tmp31) >> 16) & 0xFF;
tmp32[2] = (uint32_t(tmp31) >> 8) & 0xFF;
tmp32[3] = (uint32_t(tmp31) >> 0) & 0xFF;
in.append(tmp32, 4);
in.append(in0.SetProxy);
}
}
char *out = NULL;
@ -138,21 +148,6 @@ RunDownload_Resp RunDownload(RunDownload_Req in0){
RunDownload_Resp retValue;
int outIdx = 0;
{
{
uint32_t tmp28 = 0;
uint32_t tmp29 = uint32_t(uint8_t(out[outIdx+0]) << 24);
uint32_t tmp30 = uint32_t(uint8_t(out[outIdx+1]) << 16);
uint32_t tmp31 = uint32_t(uint8_t(out[outIdx+2]) << 8);
uint32_t tmp32 = uint32_t(uint8_t(out[outIdx+3]) << 0);
tmp28 = tmp29 | tmp30 | tmp31 | tmp32;
outIdx+=4;
retValue.ErrMsg = std::string(out+outIdx, out+outIdx+tmp28);
outIdx+=tmp28;
}
retValue.IsSkipped = (bool) out[outIdx];
outIdx++;
retValue.IsCancel = (bool) out[outIdx];
outIdx++;
{
uint32_t tmp33 = 0;
uint32_t tmp34 = uint32_t(uint8_t(out[outIdx+0]) << 24);
@ -161,9 +156,24 @@ RunDownload_Resp RunDownload(RunDownload_Req in0){
uint32_t tmp37 = uint32_t(uint8_t(out[outIdx+3]) << 0);
tmp33 = tmp34 | tmp35 | tmp36 | tmp37;
outIdx+=4;
retValue.SaveFileTo = std::string(out+outIdx, out+outIdx+tmp33);
retValue.ErrMsg = std::string(out+outIdx, out+outIdx+tmp33);
outIdx+=tmp33;
}
retValue.IsSkipped = (bool) out[outIdx];
outIdx++;
retValue.IsCancel = (bool) out[outIdx];
outIdx++;
{
uint32_t tmp38 = 0;
uint32_t tmp39 = uint32_t(uint8_t(out[outIdx+0]) << 24);
uint32_t tmp40 = uint32_t(uint8_t(out[outIdx+1]) << 16);
uint32_t tmp41 = uint32_t(uint8_t(out[outIdx+2]) << 8);
uint32_t tmp42 = uint32_t(uint8_t(out[outIdx+3]) << 0);
tmp38 = tmp39 | tmp40 | tmp41 | tmp42;
outIdx+=4;
retValue.SaveFileTo = std::string(out+outIdx, out+outIdx+tmp38);
outIdx+=tmp38;
}
}
if (out != NULL) {
free(out);

View File

@ -3,6 +3,7 @@
#include <string>
#include <vector>
#include <cstdint>
#include <map>
//Qt Creator 需要在xxx.pro 内部增加静态库的链接声明
//LIBS += -L$$PWD -lm3u8d-impl
@ -13,18 +14,22 @@ struct RunDownload_Req{
std::string SaveDir;
std::string FileName;
int32_t SkipTsCountFromHead;
std::string SetProxy;
RunDownload_Req(): Insecure(false),SkipTsCountFromHead(0){}
};
struct RunDownload_Resp{
std::string ErrMsg;
bool IsSkipped;
bool IsCancel;
std::string SaveFileTo;
RunDownload_Resp(): IsSkipped(false),IsCancel(false){}
};
RunDownload_Resp RunDownload(RunDownload_Req in0);
void CloseOldEnv();
struct GetProgress_Resp{
int32_t Percent;
std::string Title;
GetProgress_Resp(): Percent(0){}
};
GetProgress_Resp GetProgress();
std::string GetWd();

View File

@ -35,6 +35,7 @@ void MainWindow::on_pushButton_RunDownload_clicked()
ui->pushButton_RunDownload->setEnabled(false);
ui->checkBox_Insecure->setEnabled(false);
ui->progressBar->setValue(0);
ui->lineEdit_SetProxy->setEnabled(false);
ui->pushButton_StopDownload->setEnabled(true);
m_syncUi.AddRunFnOn_OtherThread([this](){
@ -62,6 +63,7 @@ void MainWindow::on_pushButton_RunDownload_clicked()
req.SaveDir = ui->lineEdit_SaveDir->text().toStdString();
req.FileName = ui->lineEdit_FileName->text().toStdString();
req.SkipTsCountFromHead = ui->lineEdit_SkipTsCountFromHead->text().toInt();
req.SetProxy = ui->lineEdit_SetProxy->text().toStdString();
m_syncUi.AddRunFnOn_OtherThread([req, this](){
RunDownload_Resp resp = RunDownload(req);
@ -75,6 +77,7 @@ void MainWindow::on_pushButton_RunDownload_clicked()
ui->pushButton_RunDownload->setEnabled(true);
ui->checkBox_Insecure->setEnabled(true);
ui->pushButton_RunDownload->setText("开始下载");
ui->lineEdit_SetProxy->setEnabled(true);
ui->pushButton_StopDownload->setEnabled(false);
if (resp.IsCancel) {
return;

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>747</width>
<height>247</height>
<width>802</width>
<height>260</height>
</rect>
</property>
<property name="windowTitle">
@ -18,21 +18,21 @@
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="4" column="0">
<widget class="QLabel" name="label_6">
<widget class="QLabel" name="label_3">
<property name="text">
<string>HostType</string>
<string>代理设置</string>
</property>
</widget>
</item>
<item row="1" column="3">
<widget class="QPushButton" name="pushButton_SaveDir">
<item row="3" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>...</string>
<string>跳过前面几个TS</string>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QLineEdit" name="lineEdit_SkipTsCountFromHead"/>
<item row="1" column="1">
<widget class="QLineEdit" name="lineEdit_SaveDir"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_4">
@ -41,17 +41,46 @@
</property>
</widget>
</item>
<item row="2" column="2">
<item row="0" column="1">
<widget class="QLineEdit" name="lineEdit_M3u8Url">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="lineEdit_SkipTsCountFromHead"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>保存位置</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="lineEdit_FileName">
<property name="placeholderText">
<string>all</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<item row="1" column="2">
<widget class="QPushButton" name="pushButton_SaveDir">
<property name="minimumSize">
<size>
<width>40</width>
<height>40</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
<property name="text">
<string>保存位置</string>
<string>...</string>
</property>
</widget>
</item>
@ -62,17 +91,7 @@
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLineEdit" name="lineEdit_M3u8Url">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QLineEdit" name="lineEdit_SaveDir"/>
</item>
<item row="4" column="2">
<item row="5" column="1">
<widget class="QComboBox" name="comboBox_HostType">
<item>
<property name="text">
@ -86,10 +105,20 @@
</item>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_5">
<item row="5" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>跳过前面几个TS</string>
<string>HostType</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLineEdit" name="lineEdit_SetProxy">
<property name="text">
<string/>
</property>
<property name="placeholderText">
<string>http://127.0.0.1:8080 socks5://127.0.0.1:1089</string>
</property>
</widget>
</item>

101
proxy.go Normal file
View File

@ -0,0 +1,101 @@
package m3u8d
import (
"bufio"
"bytes"
"context"
"crypto/tls"
"encoding/base64"
"errors"
"fmt"
"golang.org/x/net/proxy"
"net"
"net/http"
"net/url"
"strings"
)
func newDialContext(setProxy string) func(ctx context.Context, network, addr string) (net.Conn, error) {
return func(ctx context.Context, network, addr string) (net.Conn, error) {
if setProxy == "" {
return (&net.Dialer{}).DialContext(ctx, network, addr)
} else if strings.HasPrefix(setProxy, "http") {
return proxyByHttp(setProxy, ctx, addr)
} else { // socks5
urlObj, err := url.Parse(setProxy)
if err != nil {
return nil, err
}
dialer, err := proxy.FromURL(urlObj, nil)
if err != nil {
return nil, err
}
return dialer.Dial(network, addr)
}
}
}
func proxyByHttp(setProxy string, ctx context.Context, to string) (net.Conn, error) {
// https://github.com/aidenesco/connect/blob/master/proxy.go
urlObj, err := url.Parse(setProxy)
if err != nil {
return nil, err
}
var tConn net.Conn
if strings.HasPrefix(setProxy, "https://") {
host := urlObj.Host
_, _, err = net.SplitHostPort(host)
if err != nil {
host = host + ":443"
}
tConn, err = (&tls.Dialer{}).DialContext(ctx, "tcp", host)
} else {
host := urlObj.Host
_, _, err = net.SplitHostPort(host)
if err != nil {
host = host + ":80"
}
tConn, err = (&net.Dialer{}).DialContext(ctx, "tcp", host)
}
if err != nil {
return nil, err
}
defer func() {
if err != nil {
tConn.Close()
}
}()
buf0 := bytes.NewBuffer(nil)
buf0.WriteString(`CONNECT ` + to + ` HTTP/1.1` + "\r\n")
if u := urlObj.User; u != nil {
username := u.Username()
password, _ := u.Password()
buf0.WriteString("Proxy-Authorization: Basic " + base64.StdEncoding.EncodeToString([]byte(username+":"+password)) + "\r\n")
}
buf0.WriteString("\r\n")
_, err = tConn.Write(buf0.Bytes())
if err != nil {
return nil, err
}
bufr := bufio.NewReader(tConn)
var response *http.Response
response, err = http.ReadResponse(bufr, nil)
if err != nil {
return nil, err
}
switch response.StatusCode {
case http.StatusOK:
return tConn, nil
case http.StatusProxyAuthRequired:
return nil, errors.New("connect: invalid or missing \"Proxy-Authorization\" header")
default:
return nil, fmt.Errorf("connect: unexpected CONNECT response status \"%s\" (expect 200 OK)", response.Status)
}
}