Merge branch 'master' into code-cleanup

This commit is contained in:
Martin Dosch 2022-04-25 12:12:20 +02:00
commit a3bebd365b
2 changed files with 51 additions and 100 deletions

View File

@ -7,6 +7,7 @@ package main
import ( import (
"bytes" "bytes"
"encoding/xml" "encoding/xml"
"fmt"
"log" "log"
"net/http" "net/http"
"os" "os"
@ -14,14 +15,12 @@ import (
"regexp" "regexp"
"strconv" "strconv"
"github.com/gabriel-vasile/mimetype" // MIT License "github.com/beevik/etree" // BSD-2-clause
"github.com/gabriel-vasile/mimetype" // MIT License)
"github.com/mattn/go-xmpp" // BSD-3-Clause "github.com/mattn/go-xmpp" // BSD-3-Clause
) )
func httpUpload(client *xmpp.Client, jserver string, filePath string) string { func httpUpload(client *xmpp.Client, jserver string, filePath string) string {
var iqDiscoItemsXML IQDiscoItemsType
var iqDiscoInfoXML IQDiscoInfoType
var iqHttpUploadSlotXML IQHttpUploadSlot
var uploadComponent string var uploadComponent string
var maxFileSize int64 var maxFileSize int64
@ -59,14 +58,18 @@ func httpUpload(client *xmpp.Client, jserver string, filePath string) string {
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
err = xml.Unmarshal(iqContent.Query, &iqDiscoItemsXML) iqDiscoItemsXML := etree.NewDocument()
err = iqDiscoItemsXML.ReadFromBytes(iqContent.Query)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
iqDiscoItemsXMLQuery := iqDiscoItemsXML.SelectElement("query")
iqDiscoItemsXMLItems := iqDiscoItemsXMLQuery.SelectElements("item")
// Check the services reported by disco#items for the http upload service // Check the services reported by disco#items for the http upload service
for _, r := range iqDiscoItemsXML.Item { for _, r := range iqDiscoItemsXMLItems {
iqDiscoInfo, err := sendIQ(client, r.Jid, "get", jid := r.SelectAttr("jid")
iqDiscoInfo, err := sendIQ(client, jid.Value, "get",
"<query xmlns='http://jabber.org/protocol/disco#info'/>") "<query xmlns='http://jabber.org/protocol/disco#info'/>")
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
@ -74,23 +77,34 @@ func httpUpload(client *xmpp.Client, jserver string, filePath string) string {
if iqDiscoInfo.Type != "result" { if iqDiscoInfo.Type != "result" {
continue continue
} }
err = xml.Unmarshal(iqDiscoInfo.Query, &iqDiscoInfoXML) iqDiscoInfoXML := etree.NewDocument()
err = iqDiscoInfoXML.ReadFromBytes(iqDiscoInfo.Query)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
iqDiscoInfoXMLQuery := iqDiscoInfoXML.SelectElement("query")
iqDiscoInfoXMLIdentity := iqDiscoInfoXMLQuery.SelectElement("identity")
iqDiscoInfoXMLType := iqDiscoInfoXMLIdentity.SelectAttr("type")
iqDiscoInfoXMLCategory := iqDiscoInfoXMLIdentity.SelectAttr("category")
if iqDiscoInfoXML.Identity.Type == "file" && iqDiscoInfoXML.Identity.Category == "store" { if iqDiscoInfoXMLType.Value == "file" &&
uploadComponent = r.Jid iqDiscoInfoXMLCategory.Value == "store" {
uploadComponent = jid.Value
} }
} }
if uploadComponent == "" { if uploadComponent == "" {
log.Fatal("No http upload component found.") log.Fatal("No http upload component found.")
} }
for _, r := range iqDiscoInfoXML.X { iqDiscoInfoXMLX := iqDiscoItemsXMLQuery.SelectElements("x")
for i, t := range r.Field { for _, r := range iqDiscoInfoXMLX {
if t.Var == "max-file-size" && r.Field[i-1].Value == nsHttpUpload { field := r.SelectElements("field")
maxFileSize, err = strconv.ParseInt(t.Value, 10, 64) for i, t := range field {
varAttr := t.SelectAttr("var")
prevFieldVal := field[i-1].SelectElement("value")
curFieldVal := t.SelectElement("value")
if varAttr.Value == "max-file-size" && prevFieldVal.Text() == nsHttpUpload {
maxFileSize, err = strconv.ParseInt(curFieldVal.Text(), 10, 64)
if err != nil { if err != nil {
log.Fatal("Error while checking server maximum http upload file size.") log.Fatal("Error while checking server maximum http upload file size.")
} }
@ -108,40 +122,48 @@ func httpUpload(client *xmpp.Client, jserver string, filePath string) string {
} }
} }
var request IQHttpUploadSlotRequest request := etree.NewDocument()
request.Xmlns = nsHttpUpload requestReq := request.CreateElement("request")
request.FileName = fileNameEscaped requestReq.CreateAttr("xmlns", nsHttpUpload)
request.FileSize = fileSize requestReq.CreateAttr("filename", fileNameEscaped)
request.FileType = mimeType requestReq.CreateAttr("size", fmt.Sprint(fileSize))
r, err := xml.Marshal(request) requestReq.CreateAttr("content-type", mimeType)
r, err := request.WriteToString()
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
// Request http upload slot // Request http upload slot
uploadSlot, err := sendIQ(client, uploadComponent, "get", string(r)) uploadSlot, err := sendIQ(client, uploadComponent, "get", r)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
if uploadSlot.Type != "result" { if uploadSlot.Type != "result" {
log.Fatal("Error while requesting upload slot.") log.Fatal("Error while requesting upload slot.")
} }
err = xml.Unmarshal(uploadSlot.Query, &iqHttpUploadSlotXML) iqHttpUploadSlotXML := etree.NewDocument()
err = iqHttpUploadSlotXML.ReadFromBytes(uploadSlot.Query)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
iqHttpUploadSlotXMLSlot := iqHttpUploadSlotXML.SelectElement("slot")
iqHttpUploadSlotXMLPut := iqHttpUploadSlotXMLSlot.SelectElement("put")
iqHttpUploadSlotXMLPutURL := iqHttpUploadSlotXMLPut.SelectAttr("url")
// Upload file // Upload file
httpClient := &http.Client{} httpClient := &http.Client{}
req, err := http.NewRequest(http.MethodPut, iqHttpUploadSlotXML.Put.URL, buffer) req, err := http.NewRequest(http.MethodPut, iqHttpUploadSlotXMLPutURL.Value,
buffer)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
req.Header.Set("Content-Type", mimeTypeEscaped.String()) req.Header.Set("Content-Type", mimeTypeEscaped.String())
for _, h := range iqHttpUploadSlotXML.Put.Headers { iqHttpUploadSlotXMLPutHeaders := iqHttpUploadSlotXMLPut.SelectElements("header")
switch h.Name { for _, h := range iqHttpUploadSlotXMLPutHeaders {
name := h.SelectAttr("name")
switch name.Value {
case "Authorization", "Cookie", "Expires": case "Authorization", "Cookie", "Expires":
req.Header.Set(h.Name, h.Value) req.Header.Set(name.Value, h.Text())
} }
} }
resp, err := httpClient.Do(req) resp, err := httpClient.Do(req)
@ -154,5 +176,7 @@ func httpUpload(client *xmpp.Client, jserver string, filePath string) string {
} }
// Return http link // Return http link
return iqHttpUploadSlotXML.Get.URL iqHttpUploadSlotXMLGet := iqHttpUploadSlotXMLSlot.SelectElement("get")
iqHttpUploadSlotXMLGetURL := iqHttpUploadSlotXMLGet.SelectAttr("url")
return iqHttpUploadSlotXMLGetURL.Value
} }

View File

@ -1,73 +0,0 @@
// Copyright 2022 Martin Dosch.
// Use of this source code is governed by the BSD-2-clause
// license that can be found in the LICENSE file.
package main
import "encoding/xml"
// Created with https://github.com/miku/zek
type IQDiscoItemsType struct {
XMLName xml.Name `xml:"query"`
Text string `xml:",chardata"`
Xmlns string `xml:"xmlns,attr"`
Item []struct {
Text string `xml:",chardata"`
Jid string `xml:"jid,attr"`
} `xml:"item"`
}
// Created with https://github.com/miku/zek
type IQDiscoInfoType struct {
XMLName xml.Name `xml:"query"`
Text string `xml:",chardata"`
Xmlns string `xml:"xmlns,attr"`
Identity struct {
Text string `xml:",chardata"`
Type string `xml:"type,attr"`
Name string `xml:"name,attr"`
Category string `xml:"category,attr"`
} `xml:"identity"`
Feature []struct {
Text string `xml:",chardata"`
Var string `xml:"var,attr"`
} `xml:"feature"`
X []struct {
Text string `xml:",chardata"`
Type string `xml:"type,attr"`
Xmlns string `xml:"xmlns,attr"`
Field []struct {
Text string `xml:",chardata"`
Type string `xml:"type,attr"`
Var string `xml:"var,attr"`
Value string `xml:"value"`
} `xml:"field"`
} `xml:"x"`
}
type IQHttpUploadSlotRequest struct {
XMLName xml.Name `xml:"request"`
Xmlns string `xml:"xmlns,attr"`
FileName string `xml:"filename,attr"`
FileType string `xml:"mime-type,attr"`
FileSize int64 `xml:"size,attr"`
}
// Created with https://github.com/miku/zek
type IQHttpUploadSlot struct {
XMLName xml.Name `xml:"slot"`
Text string `xml:",chardata"`
Xmlns string `xml:"xmlns,attr"`
Get struct {
Text string `xml:",chardata"`
URL string `xml:"url,attr"`
} `xml:"get"`
Put struct {
Text string `xml:",chardata"`
URL string `xml:"url,attr"`
Headers []struct {
Name string `xml:"name,attr"`
Value string `xml:",chardata"`
} `xml:"header"`
} `xml:"put"`
}