mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-05-07 06:02:09 +08:00
172 lines
4.3 KiB
Go
172 lines
4.3 KiB
Go
// Copyright 2019 Yunion
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package appsrv
|
|
|
|
import (
|
|
"encoding/xml"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"strconv"
|
|
"time"
|
|
|
|
"yunion.io/x/jsonutils"
|
|
"yunion.io/x/log"
|
|
"yunion.io/x/pkg/errors"
|
|
"yunion.io/x/pkg/gotypes"
|
|
)
|
|
|
|
func SendNoContent(w http.ResponseWriter) {
|
|
w.WriteHeader(204)
|
|
sendBytes(w, []byte{})
|
|
}
|
|
|
|
func Send(w http.ResponseWriter, text string) {
|
|
w.Header().Set("Content-Type", "text/plain;charset=utf-8")
|
|
sendBytes(w, []byte(text))
|
|
}
|
|
|
|
func SendHTML(w http.ResponseWriter, text string) {
|
|
w.Header().Set("Content-Type", "text/html;charset=utf-8")
|
|
sendBytes(w, []byte(text))
|
|
}
|
|
|
|
func sendBytes(w http.ResponseWriter, output []byte) {
|
|
w.Header().Set("Content-Length", strconv.FormatInt(int64(len(output)), 10))
|
|
w.Write(output)
|
|
}
|
|
|
|
func SendStruct(w http.ResponseWriter, obj interface{}) {
|
|
jsonObj := jsonutils.Marshal(obj)
|
|
SendJSON(w, jsonObj)
|
|
}
|
|
|
|
func SendJSON(w http.ResponseWriter, obj jsonutils.JSONObject) {
|
|
var output []byte
|
|
w.Header().Set("Content-Type", "application/json;charset=utf-8")
|
|
if obj != nil {
|
|
output = []byte(obj.String())
|
|
}
|
|
sendBytes(w, output)
|
|
}
|
|
|
|
func SendHeader(w http.ResponseWriter, hdr http.Header) {
|
|
for k, v := range hdr {
|
|
if len(v) > 0 && len(v[0]) > 0 {
|
|
w.Header().Set(k, v[0])
|
|
}
|
|
}
|
|
w.WriteHeader(204)
|
|
w.Write([]byte{})
|
|
}
|
|
|
|
func SendXml(w http.ResponseWriter, hdr http.Header, obj interface{}) {
|
|
SendXmlWithIndent(w, hdr, obj, false)
|
|
}
|
|
|
|
func SendXmlWithIndent(w http.ResponseWriter, hdr http.Header, obj interface{}, indent bool) {
|
|
if !gotypes.IsNil(obj) {
|
|
var xmlBytes []byte
|
|
var err error
|
|
if indent {
|
|
xmlBytes, err = xml.MarshalIndent(obj, "", " ")
|
|
} else {
|
|
xmlBytes, err = xml.Marshal(obj)
|
|
}
|
|
if err == nil {
|
|
for k, v := range hdr {
|
|
if k != "Content-Type" && k != "Content-Length" {
|
|
w.Header().Set(k, v[0])
|
|
}
|
|
}
|
|
w.Header().Set("Content-Type", "application/xml;charset=utf-8")
|
|
w.Header().Set("Content-Length", strconv.FormatInt(int64(len(xmlBytes)+len(xml.Header)), 10))
|
|
w.Write([]byte(xml.Header))
|
|
w.Write(xmlBytes)
|
|
} else {
|
|
w.WriteHeader(400)
|
|
Send(w, err.Error())
|
|
}
|
|
} else {
|
|
for k, v := range hdr {
|
|
if k != "Content-Type" && k != "Content-Length" {
|
|
w.Header().Set(k, v[0])
|
|
}
|
|
}
|
|
SendNoContent(w)
|
|
}
|
|
}
|
|
|
|
func SendStream(w http.ResponseWriter, isPartial bool, hdr http.Header, stream io.ReadCloser, sizeBytes int64) error {
|
|
defer stream.Close()
|
|
for k, v := range hdr {
|
|
if k != "Content-Length" {
|
|
log.Debugf("send %s %s", k, v)
|
|
w.Header().Set(k, v[0])
|
|
}
|
|
}
|
|
if sizeBytes > 0 {
|
|
log.Debugf("send content-length %d", sizeBytes)
|
|
w.Header().Set("Content-Length", strconv.FormatInt(sizeBytes, 10))
|
|
}
|
|
if isPartial {
|
|
log.Debugf("send partial 206")
|
|
w.WriteHeader(206)
|
|
} else {
|
|
log.Debugf("send full 200")
|
|
w.WriteHeader(200)
|
|
}
|
|
offset := 0
|
|
buf := make([]byte, 4096)
|
|
for sizeBytes <= 0 || int64(offset) < sizeBytes {
|
|
n, err := stream.Read(buf)
|
|
if n > 0 {
|
|
woff := 0
|
|
for woff < n {
|
|
m, err := w.Write(buf[woff:n])
|
|
if err != nil {
|
|
return errors.Wrap(err, fmt.Sprintf("w.Write read_offset %d write_offset %d", offset, woff))
|
|
}
|
|
woff += m
|
|
}
|
|
offset += n
|
|
}
|
|
if err != nil {
|
|
if err == io.EOF {
|
|
break
|
|
}
|
|
return errors.Wrap(err, "stream.Read")
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func SendRedirect(w http.ResponseWriter, redirectUrl string) {
|
|
w.Header().Set("Location", redirectUrl)
|
|
w.WriteHeader(302)
|
|
w.Write([]byte{})
|
|
}
|
|
|
|
func DisableClientCache(w http.ResponseWriter) {
|
|
// disable client cache
|
|
// Expires: Tue, 03 Jul 2001 06:00:00 GMT
|
|
// Last-Modified: {now} GMT
|
|
// Cache-Control: max-age=0, no-cache, must-revalidate, proxy-revalidate
|
|
w.Header().Set("Expires", "Tue, 03 Jul 2001 06:00:00 GMT")
|
|
cacheSince := time.Now().Format(http.TimeFormat)
|
|
w.Header().Set("Last-Modified", cacheSince)
|
|
w.Header().Set("Cache-Control", "max-age=0, no-cache, must-revalidate, proxy-revalidate")
|
|
}
|