* Add GET requests to webhook * make fmt * Handle invalid http method on webhook * Uppercase http method in webhook * Rename v85.go to v86.go * make fmttags/v1.9.0-rc1
@@ -225,6 +225,8 @@ var migrations = []Migration{ | |||
NewMigration("add table to store original imported gpg keys", addGPGKeyImport), | |||
// v85 -> v86 | |||
NewMigration("hash application token", hashAppToken), | |||
// v86 -> v87 | |||
NewMigration("add http method to webhook", addHTTPMethodToWebhook), | |||
} | |||
// Migrate database to current version |
@@ -0,0 +1,17 @@ | |||
// Copyright 2019 The Gitea Authors. All rights reserved. | |||
// Use of this source code is governed by a MIT-style | |||
// license that can be found in the LICENSE file. | |||
package migrations | |||
import ( | |||
"github.com/go-xorm/xorm" | |||
) | |||
func addHTTPMethodToWebhook(x *xorm.Engine) error { | |||
type Webhook struct { | |||
HTTPMethod string `xorm:"http_method DEFAULT 'POST'"` | |||
} | |||
return x.Sync2(new(Webhook)) | |||
} |
@@ -13,6 +13,7 @@ import ( | |||
"encoding/json" | |||
"fmt" | |||
"io/ioutil" | |||
"net/http" | |||
"strings" | |||
"time" | |||
@@ -105,6 +106,7 @@ type Webhook struct { | |||
OrgID int64 `xorm:"INDEX"` | |||
URL string `xorm:"url TEXT"` | |||
Signature string `xorm:"TEXT"` | |||
HTTPMethod string `xorm:"http_method"` | |||
ContentType HookContentType | |||
Secret string `xorm:"TEXT"` | |||
Events string `xorm:"TEXT"` | |||
@@ -553,6 +555,7 @@ type HookTask struct { | |||
Signature string `xorm:"TEXT"` | |||
api.Payloader `xorm:"-"` | |||
PayloadContent string `xorm:"TEXT"` | |||
HTTPMethod string `xorm:"http_method"` | |||
ContentType HookContentType | |||
EventType HookEventType | |||
IsSSL bool | |||
@@ -707,6 +710,7 @@ func prepareWebhook(e Engine, w *Webhook, repo *Repository, event HookEventType, | |||
URL: w.URL, | |||
Signature: signature, | |||
Payloader: payloader, | |||
HTTPMethod: w.HTTPMethod, | |||
ContentType: w.ContentType, | |||
EventType: event, | |||
IsSSL: w.IsSSL, | |||
@@ -751,9 +755,32 @@ func prepareWebhooks(e Engine, repo *Repository, event HookEventType, p api.Payl | |||
func (t *HookTask) deliver() { | |||
t.IsDelivered = true | |||
t.RequestInfo = &HookRequest{ | |||
Headers: map[string]string{}, | |||
} | |||
t.ResponseInfo = &HookResponse{ | |||
Headers: map[string]string{}, | |||
} | |||
timeout := time.Duration(setting.Webhook.DeliverTimeout) * time.Second | |||
req := httplib.Post(t.URL).SetTimeout(timeout, timeout). | |||
var req *httplib.Request | |||
if t.HTTPMethod == http.MethodPost { | |||
req = httplib.Post(t.URL) | |||
switch t.ContentType { | |||
case ContentTypeJSON: | |||
req = req.Header("Content-Type", "application/json").Body(t.PayloadContent) | |||
case ContentTypeForm: | |||
req.Param("payload", t.PayloadContent) | |||
} | |||
} else if t.HTTPMethod == http.MethodGet { | |||
req = httplib.Get(t.URL).Param("payload", t.PayloadContent) | |||
} else { | |||
t.ResponseInfo.Body = fmt.Sprintf("Invalid http method: %v", t.HTTPMethod) | |||
return | |||
} | |||
req = req.SetTimeout(timeout, timeout). | |||
Header("X-Gitea-Delivery", t.UUID). | |||
Header("X-Gitea-Event", string(t.EventType)). | |||
Header("X-Gitea-Signature", t.Signature). | |||
@@ -764,25 +791,11 @@ func (t *HookTask) deliver() { | |||
HeaderWithSensitiveCase("X-GitHub-Event", string(t.EventType)). | |||
SetTLSClientConfig(&tls.Config{InsecureSkipVerify: setting.Webhook.SkipTLSVerify}) | |||
switch t.ContentType { | |||
case ContentTypeJSON: | |||
req = req.Header("Content-Type", "application/json").Body(t.PayloadContent) | |||
case ContentTypeForm: | |||
req.Param("payload", t.PayloadContent) | |||
} | |||
// Record delivery information. | |||
t.RequestInfo = &HookRequest{ | |||
Headers: map[string]string{}, | |||
} | |||
for k, vals := range req.Headers() { | |||
t.RequestInfo.Headers[k] = strings.Join(vals, ",") | |||
} | |||
t.ResponseInfo = &HookResponse{ | |||
Headers: map[string]string{}, | |||
} | |||
defer func() { | |||
t.Delivered = time.Now().UnixNano() | |||
if t.IsSucceed { |
@@ -196,6 +196,7 @@ func (f WebhookForm) ChooseEvents() bool { | |||
// NewWebhookForm form for creating web hook | |||
type NewWebhookForm struct { | |||
PayloadURL string `binding:"Required;ValidUrl"` | |||
HTTPMethod string `binding:"Required;In(POST,GET)"` | |||
ContentType int `binding:"Required"` | |||
Secret string | |||
WebhookForm |
@@ -1192,6 +1192,7 @@ settings.githook_content = Hook Content | |||
settings.update_githook = Update Hook | |||
settings.add_webhook_desc = Gitea will send <code>POST</code> requests with a specified content type to the target URL. Read more in the <a target="_blank" rel="noopener noreferrer" href="%s">webhooks guide</a>. | |||
settings.payload_url = Target URL | |||
settings.http_method = HTTP Method | |||
settings.content_type = POST Content Type | |||
settings.secret = Secret | |||
settings.slack_username = Username |
@@ -1430,6 +1430,15 @@ function initWebhook() { | |||
} | |||
}); | |||
var updateContentType = function () { | |||
var visible = $('#http_method').val() === 'POST'; | |||
$('#content_type').parent().parent()[visible ? 'show' : 'hide'](); | |||
}; | |||
updateContentType(); | |||
$('#http_method').change(function () { | |||
updateContentType(); | |||
}); | |||
// Test delivery | |||
$('#test-delivery').click(function () { | |||
var $this = $(this); |
@@ -176,6 +176,7 @@ func WebHooksNewPost(ctx *context.Context, form auth.NewWebhookForm) { | |||
w := &models.Webhook{ | |||
RepoID: orCtx.RepoID, | |||
URL: form.PayloadURL, | |||
HTTPMethod: form.HTTPMethod, | |||
ContentType: contentType, | |||
Secret: form.Secret, | |||
HookEvent: ParseHookEvent(form.WebhookForm), |
@@ -6,6 +6,18 @@ | |||
<label for="payload_url">{{.i18n.Tr "repo.settings.payload_url"}}</label> | |||
<input id="payload_url" name="payload_url" type="url" value="{{.Webhook.URL}}" autofocus required> | |||
</div> | |||
<div class="field"> | |||
<label>{{.i18n.Tr "repo.settings.http_method"}}</label> | |||
<div class="ui selection dropdown"> | |||
<input type="hidden" id="http_method" name="http_method" value="{{if .Webhook.HTTPMethod}}{{.Webhook.HTTPMethod}}{{else}}POST{{end}}"> | |||
<div class="default text"></div> | |||
<i class="dropdown icon"></i> | |||
<div class="menu"> | |||
<div class="item" data-value="POST">POST</div> | |||
<div class="item" data-value="GET">GET</div> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="field"> | |||
<label>{{.i18n.Tr "repo.settings.content_type"}}</label> | |||
<div class="ui selection dropdown"> |