http-upload: Improved error handling.

no-tls
Martin Dosch 5 months ago
parent 2d9bdfa80a
commit 643842fcb1
No known key found for this signature in database
GPG Key ID: 52A57CFCE13D657D

@ -5,6 +5,9 @@
- Add support for `tls-server-end-point` channel binding (via go-xmpp commit 3f0cbac30767faa562ad198ee69f36055f5924bc).
- Add experimental support for SOCKS5 proxies using the `HTTP_PROXY` environment variable (requires go-xmpp commit 685570cbd85c31ea3b426bea34dd4af404aac8cf).
### Changed
- http-upload: Improved error handling.
## [v0.8.0] 2024-01-09
### Added
- Add new parameter `--scram-mech-pinning`.

@ -7,8 +7,8 @@ package main
import (
"bytes"
"encoding/xml"
"errors"
"fmt"
"log"
"net/http"
"net/url"
"os"
@ -25,21 +25,21 @@ import (
func httpUpload(client *xmpp.Client, iqc chan xmpp.IQ, jserver string, filePath string,
timeout time.Duration,
) string {
) (string, error) {
var uploadComponent string
var maxFileSize int64
// Get file size
fileInfo, err := os.Stat(filePath)
if err != nil {
log.Fatal(err)
return "", err
}
fileSize := fileInfo.Size()
// Read file
buffer, err := readFile(filePath)
if err != nil {
log.Fatal(err)
return "", err
}
// Get mime type
@ -58,16 +58,16 @@ func httpUpload(client *xmpp.Client, iqc chan xmpp.IQ, jserver string, filePath
iqContent, err := sendIQ(client, iqc, jserver, "get",
"<query xmlns='http://jabber.org/protocol/disco#items'/>")
if err != nil {
log.Fatal(err)
return "", err
}
iqDiscoItemsXML := etree.NewDocument()
err = iqDiscoItemsXML.ReadFromBytes(iqContent.Query)
if err != nil {
log.Fatal(err)
return "", err
}
iqDiscoItemsXMLQuery := iqDiscoItemsXML.SelectElement("query")
if iqDiscoItemsXMLQuery == nil {
log.Fatal("no query element in disco items reply")
return "", errors.New("http-upload: no query element in disco items reply")
}
iqDiscoItemsXMLItems := iqDiscoItemsXMLQuery.SelectElements("item")
@ -80,11 +80,11 @@ func httpUpload(client *xmpp.Client, iqc chan xmpp.IQ, jserver string, filePath
iqDiscoInfoReqXMLQuery.CreateAttr("xmlns", nsDiscoInfo)
iqdi, err := iqDiscoInfoReqXML.WriteToString()
if err != nil {
log.Fatal(err)
return "", err
}
iqDiscoInfo, err := sendIQ(client, iqc, jid.Value, "get", iqdi)
if err != nil {
log.Fatal(err)
return "", err
}
if iqDiscoInfo.Type != strResult {
continue
@ -92,7 +92,7 @@ func httpUpload(client *xmpp.Client, iqc chan xmpp.IQ, jserver string, filePath
iqDiscoInfoXML := etree.NewDocument()
err = iqDiscoInfoXML.ReadFromBytes(iqDiscoInfo.Query)
if err != nil {
log.Fatal(err)
return "", err
}
iqDiscoInfoXMLQuery := iqDiscoInfoXML.SelectElement("query")
if iqDiscoInfoXMLQuery == nil {
@ -116,9 +116,9 @@ func httpUpload(client *xmpp.Client, iqc chan xmpp.IQ, jserver string, filePath
}
}
if uploadComponent == "" {
log.Fatal("No http upload component found.")
return "", errors.New("http-upload: no http upload component found.")
}
iqDiscoInfoXMLX := iqDiscoItemsXMLQuery.SelectElements("x")
iqDiscoInfoXMLX := iqDiscoItemsXMLQuery.SelectElements("X")
for _, r := range iqDiscoInfoXMLX {
field := r.SelectElements("field")
for i, t := range field {
@ -137,7 +137,7 @@ func httpUpload(client *xmpp.Client, iqc chan xmpp.IQ, jserver string, filePath
if varAttr.Value == "max-file-size" && prevFieldVal.Text() == nsHTTPUpload {
maxFileSize, err = strconv.ParseInt(curFieldVal.Text(), 10, 64)
if err != nil {
log.Fatal("error while checking server maximum http upload file size.")
return "", errors.New("http-upload: error while checking server maximum http upload file size.")
}
}
}
@ -147,7 +147,7 @@ func httpUpload(client *xmpp.Client, iqc chan xmpp.IQ, jserver string, filePath
// the best.
if maxFileSize != 0 {
if fileSize > maxFileSize {
log.Fatal("File size " + strconv.FormatInt(fileSize/1024/1024, 10) +
return "", errors.New("http-upload: file size " + strconv.FormatInt(fileSize/1024/1024, 10) +
" MB is larger than the maximum file size allowed (" +
strconv.FormatInt(maxFileSize/1024/1024, 10) + " MB).")
}
@ -162,36 +162,36 @@ func httpUpload(client *xmpp.Client, iqc chan xmpp.IQ, jserver string, filePath
requestReq.CreateAttr("content-type", mimeType)
r, err := request.WriteToString()
if err != nil {
log.Fatal(err)
return "", err
}
// Request http upload slot
uploadSlot, err := sendIQ(client, iqc, uploadComponent, "get", r)
if err != nil {
log.Fatal(err)
return "", err
}
if uploadSlot.Type != strResult {
log.Fatal("error while requesting upload slot.")
return "", errors.New("http-upload: error while requesting upload slot.")
}
iqHTTPUploadSlotXML := etree.NewDocument()
err = iqHTTPUploadSlotXML.ReadFromBytes(uploadSlot.Query)
if err != nil {
log.Fatal(err)
return "", err
}
iqHTTPUploadSlotXMLSlot := iqHTTPUploadSlotXML.SelectElement("slot")
if iqHTTPUploadSlotXMLSlot == nil {
log.Fatal("http-upload: no slot element")
return "", errors.New("http-upload: no slot element")
}
iqHTTPUploadSlotXMLPut := iqHTTPUploadSlotXMLSlot.SelectElement("put")
if iqHTTPUploadSlotXMLPut == nil {
log.Fatal("http-upload: no put element")
return "", errors.New("http-upload: no put element")
}
iqHTTPUploadSlotXMLPutURL := iqHTTPUploadSlotXMLPut.SelectAttr("url")
if iqHTTPUploadSlotXMLPutURL == nil {
log.Fatal("http-upload: no url attribute")
return "", errors.New("http-upload: no url attribute")
}
if !strings.HasPrefix(iqHTTPUploadSlotXMLPutURL.Value, "https://") {
log.Fatal("http-upload: upload slot does not provide https")
return "", errors.New("http-upload: upload slot does not provide https")
}
// Upload file
httpTransport := &http.Transport{
@ -202,7 +202,7 @@ func httpUpload(client *xmpp.Client, iqc chan xmpp.IQ, jserver string, filePath
if proxyEnv != "" {
proxyURL, err := url.Parse(proxyEnv)
if err != nil {
log.Fatal(err)
return "", err
}
httpTransport.Proxy = http.ProxyURL(proxyURL)
}
@ -210,7 +210,7 @@ func httpUpload(client *xmpp.Client, iqc chan xmpp.IQ, jserver string, filePath
req, err := http.NewRequest(http.MethodPut, iqHTTPUploadSlotXMLPutURL.Value,
buffer)
if err != nil {
log.Fatal(err)
return "", err
}
req.Header.Set("Content-Type", mimeTypeEscaped.String())
iqHTTPUploadSlotXMLPutHeaders := iqHTTPUploadSlotXMLPut.SelectElements("header")
@ -226,25 +226,25 @@ func httpUpload(client *xmpp.Client, iqc chan xmpp.IQ, jserver string, filePath
}
resp, err := httpClient.Do(req)
if err != nil {
log.Fatal(err)
return "", err
}
// Test for http status code "200 OK" or "201 Created"
if resp.StatusCode != 200 && resp.StatusCode != 201 {
log.Fatal("Http upload failed.")
return "", errors.New("http-upload: upload failed.")
}
// Return http link
iqHTTPUploadSlotXMLGet := iqHTTPUploadSlotXMLSlot.SelectElement("get")
if iqHTTPUploadSlotXMLGet == nil {
log.Fatal("http-upload: no get element")
return "", errors.New("http-upload: no get element")
}
iqHTTPUploadSlotXMLGetURL := iqHTTPUploadSlotXMLGet.SelectAttr("url")
if iqHTTPUploadSlotXMLGetURL == nil {
log.Fatal("http-upload: no url attribute")
return "", errors.New("http-upload: no url attribute")
}
err = resp.Body.Close()
if err != nil {
fmt.Println("error while closing http request body:", err)
}
return iqHTTPUploadSlotXMLGetURL.Value
return iqHTTPUploadSlotXMLGetURL.Value, nil
}

@ -8,6 +8,7 @@ import (
"bufio"
"context"
"crypto/tls"
"errors"
"fmt"
"io"
"log"
@ -30,6 +31,17 @@ type configuration struct {
alias string
}
func closeAndExit(client *xmpp.Client, cancel context.CancelFunc, err error) {
// Wait for a short time as some messages are not delivered by the server
// if the connection is closed immediately after sending a message.
time.Sleep(defaultSleepTime * time.Millisecond)
cancel()
client.Close()
if err != nil {
log.Fatal(err)
}
}
func readMessage(messageFilePath string) (string, error) {
var (
output string
@ -324,7 +336,7 @@ func main() {
for i, recipient := range recipients {
validatedJid, err := MarshalJID(recipient.Jid)
if err != nil {
log.Fatal(err)
closeAndExit(client, cancel, err)
}
recipients[i].Jid = validatedJid
}
@ -333,58 +345,61 @@ func main() {
case *flagOxGenPrivKeyX25519:
validatedOwnJid, err := MarshalJID(user)
if err != nil {
log.Fatal(err)
closeAndExit(client, cancel, err)
}
err = oxGenPrivKey(validatedOwnJid, client, iqc, *flagOxPassphrase, "x25519")
if err != nil {
log.Fatal(err)
closeAndExit(client, cancel, err)
}
os.Exit(0)
case *flagOxGenPrivKeyRSA:
validatedOwnJid, err := MarshalJID(user)
if err != nil {
log.Fatal(err)
closeAndExit(client, cancel, err)
}
err = oxGenPrivKey(validatedOwnJid, client, iqc, *flagOxPassphrase, "rsa")
if err != nil {
log.Fatal(err)
closeAndExit(client, cancel, err)
}
os.Exit(0)
case *flagOxImportPrivKey != "":
validatedOwnJid, err := MarshalJID(user)
if err != nil {
log.Fatal(err)
closeAndExit(client, cancel, err)
}
err = oxImportPrivKey(validatedOwnJid, *flagOxImportPrivKey,
client, iqc)
if err != nil {
log.Fatal(err)
closeAndExit(client, cancel, err)
}
os.Exit(0)
case *flagOxDeleteNodes:
validatedOwnJid, err := MarshalJID(user)
if err != nil {
log.Fatal(err)
closeAndExit(client, cancel, err)
}
err = oxDeleteNodes(validatedOwnJid, client, iqc)
if err != nil {
log.Fatal(err)
closeAndExit(client, cancel, err)
}
os.Exit(0)
case *flagOx:
validatedOwnJid, err := MarshalJID(user)
if err != nil {
log.Fatal(err)
closeAndExit(client, cancel, err)
}
oxPrivKey, err = oxGetPrivKey(validatedOwnJid, *flagOxPassphrase)
if err != nil {
log.Fatal(err)
closeAndExit(client, cancel, err)
}
}
if *flagHTTPUpload != "" {
message = httpUpload(client, iqc, tlsConfig.ServerName,
message, err = httpUpload(client, iqc, tlsConfig.ServerName,
*flagHTTPUpload, timeout)
if err != nil {
closeAndExit(client, cancel, err)
}
}
if *flagOOBFile != "" {
@ -393,7 +408,7 @@ func main() {
// Check if the URI is valid.
uri, err := validURI(message)
if err != nil {
log.Fatal(err)
closeAndExit(client, cancel, err)
}
message = uri.String()
}
@ -416,7 +431,7 @@ func main() {
_, err = client.JoinMUCNoHistory(recipient.Jid, alias)
}
if err != nil {
log.Fatal(err)
closeAndExit(client, cancel, err)
}
}
}
@ -428,7 +443,7 @@ func main() {
// Send raw XML
_, err = client.SendOrg(message)
if err != nil {
log.Fatal(err)
closeAndExit(client, cancel, err)
}
case *flagInteractive:
// Send in endless loop (for usage with e.g. "tail -f").
@ -447,7 +462,7 @@ func main() {
message, err = reader.ReadString('\n')
message = strings.TrimSuffix(message, "\n")
if err != nil {
log.Fatal("failed to read from stdin")
closeAndExit(client, cancel, errors.New("failed to read from stdin"))
}
// Remove invalid code points.
@ -470,7 +485,7 @@ func main() {
}
_, err = client.SendOrg(oxMessage)
if err != nil {
log.Fatal(err)
closeAndExit(client, cancel, err)
}
default:
_, err = client.Send(xmpp.Chat{
@ -478,7 +493,7 @@ func main() {
Type: msgType, Text: message,
})
if err != nil {
log.Fatal(err)
closeAndExit(client, cancel, err)
}
}
}
@ -589,7 +604,7 @@ func main() {
}
_, err = client.SendOrg(oxMessage)
if err != nil {
log.Fatal(err)
closeAndExit(client, cancel, err)
}
default:
_, err = client.Send(xmpp.Chat{
@ -597,15 +612,10 @@ func main() {
Type: msgType, Text: message,
})
if err != nil {
log.Fatal(err)
closeAndExit(client, cancel, err)
}
}
}
}
// Wait for a short time as some messages are not delivered by the server
// if the connection is closed immediately after sending a message.
time.Sleep(defaultSleepTime * time.Millisecond)
cancel()
client.Close()
closeAndExit(client, cancel, nil)
}

Loading…
Cancel
Save