2014-02-19 13:50:53 +04:00
// Copyright 2014 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
2014-05-02 05:21:46 +04:00
package cmd
2014-02-19 13:50:53 +04:00
import (
"fmt"
2016-08-12 00:46:33 +03:00
"net"
2014-02-19 13:50:53 +04:00
"net/http"
2014-11-04 04:46:53 +03:00
"net/http/fcgi"
2017-02-05 16:06:25 +03:00
_ "net/http/pprof" // Used for debugging if enabled and a web server is running
2014-04-16 04:01:20 +04:00
"os"
2014-05-26 04:11:25 +04:00
"path"
2014-09-29 13:38:46 +04:00
"strings"
2014-02-19 13:50:53 +04:00
2016-11-10 19:24:48 +03:00
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/auth"
"code.gitea.io/gitea/modules/context"
2016-12-26 04:16:37 +03:00
"code.gitea.io/gitea/modules/lfs"
2016-11-10 19:24:48 +03:00
"code.gitea.io/gitea/modules/log"
2016-12-22 21:12:23 +03:00
"code.gitea.io/gitea/modules/options"
2016-11-29 19:26:36 +03:00
"code.gitea.io/gitea/modules/public"
2016-11-10 19:24:48 +03:00
"code.gitea.io/gitea/modules/setting"
2016-12-06 20:58:31 +03:00
"code.gitea.io/gitea/modules/templates"
2016-11-10 19:24:48 +03:00
"code.gitea.io/gitea/routers"
"code.gitea.io/gitea/routers/admin"
apiv1 "code.gitea.io/gitea/routers/api/v1"
"code.gitea.io/gitea/routers/dev"
"code.gitea.io/gitea/routers/org"
"code.gitea.io/gitea/routers/repo"
"code.gitea.io/gitea/routers/user"
2016-12-26 04:16:37 +03:00
2016-11-05 19:56:35 +03:00
"github.com/go-macaron/binding"
"github.com/go-macaron/cache"
"github.com/go-macaron/captcha"
"github.com/go-macaron/csrf"
"github.com/go-macaron/gzip"
"github.com/go-macaron/i18n"
"github.com/go-macaron/session"
"github.com/go-macaron/toolbox"
"github.com/urfave/cli"
macaron "gopkg.in/macaron.v1"
2017-02-22 10:14:37 +03:00
context2 "github.com/gorilla/context"
2014-02-19 13:50:53 +04:00
)
2016-11-04 14:42:18 +03:00
// CmdWeb represents the available web sub-command.
2014-02-19 13:50:53 +04:00
var CmdWeb = cli . Command {
Name : "web" ,
2016-12-21 15:13:17 +03:00
Usage : "Start Gitea web server" ,
Description : ` Gitea web server is the only thing you need to run ,
2014-03-24 15:36:38 +04:00
and it takes care of all the other things for you ` ,
2014-02-19 13:50:53 +04:00
Action : runWeb ,
2015-02-01 20:41:03 +03:00
Flags : [ ] cli . Flag {
2016-11-10 01:18:22 +03:00
cli . StringFlag {
Name : "port, p" ,
Value : "3000" ,
Usage : "Temporary port number to prevent conflict" ,
} ,
cli . StringFlag {
Name : "config, c" ,
Value : "custom/conf/app.ini" ,
Usage : "Custom configuration file path" ,
} ,
2017-01-09 14:54:57 +03:00
cli . StringFlag {
Name : "pid, P" ,
2017-01-14 05:15:43 +03:00
Value : "/var/run/gitea.pid" ,
2017-01-09 14:54:57 +03:00
Usage : "Custom pid file path" ,
} ,
2015-02-01 20:41:03 +03:00
} ,
2014-02-19 13:50:53 +04:00
}
2016-11-04 14:42:18 +03:00
// VerChecker is a listing of required dependency versions.
2014-12-15 09:49:59 +03:00
type VerChecker struct {
ImportPath string
Version func ( ) string
Expected string
}
2014-07-26 08:24:27 +04:00
// newMacaron initializes Macaron instance.
func newMacaron ( ) * macaron . Macaron {
m := macaron . New ( )
2015-07-31 10:03:30 +03:00
if ! setting . DisableRouterLog {
m . Use ( macaron . Logger ( ) )
}
2014-07-26 08:24:27 +04:00
m . Use ( macaron . Recovery ( ) )
2014-10-14 02:04:07 +04:00
if setting . EnableGzip {
2015-10-16 04:28:12 +03:00
m . Use ( gzip . Gziper ( ) )
2014-10-14 02:04:07 +04:00
}
2014-11-16 08:06:09 +03:00
if setting . Protocol == setting . FCGI {
2016-11-27 13:14:25 +03:00
m . SetURLPrefix ( setting . AppSubURL )
2014-11-16 08:06:09 +03:00
}
2017-01-29 01:14:56 +03:00
m . Use ( public . Custom (
& public . Options {
SkipLogging : setting . DisableRouterLog ,
} ,
) )
2016-11-29 19:26:36 +03:00
m . Use ( public . Static (
& public . Options {
Directory : path . Join ( setting . StaticRootPath , "public" ) ,
2015-07-31 10:03:30 +03:00
SkipLogging : setting . DisableRouterLog ,
2014-07-26 08:24:27 +04:00
} ,
) )
2014-11-21 18:58:08 +03:00
m . Use ( macaron . Static (
setting . AvatarUploadPath ,
macaron . StaticOptions {
Prefix : "avatars" ,
2015-07-31 10:03:30 +03:00
SkipLogging : setting . DisableRouterLog ,
2017-01-25 07:26:31 +03:00
ETag : true ,
2014-11-21 18:58:08 +03:00
} ,
) )
2016-07-15 19:36:39 +03:00
2016-12-06 20:58:31 +03:00
m . Use ( templates . Renderer ( ) )
models . InitMailRender ( templates . Mailer ( ) )
2015-03-18 13:37:44 +03:00
2016-12-22 21:12:23 +03:00
localeNames , err := options . Dir ( "locale" )
2015-03-18 13:37:44 +03:00
if err != nil {
2017-01-29 23:13:57 +03:00
log . Fatal ( 4 , "Failed to list locale files: %v" , err )
2015-03-18 13:37:44 +03:00
}
2016-12-22 21:12:23 +03:00
2015-03-18 13:37:44 +03:00
localFiles := make ( map [ string ] [ ] byte )
2016-12-22 21:12:23 +03:00
2015-03-18 13:37:44 +03:00
for _ , name := range localeNames {
2016-12-22 21:12:23 +03:00
localFiles [ name ] , err = options . Locale ( name )
if err != nil {
log . Fatal ( 4 , "Failed to load %s locale file. %v" , name , err )
}
2015-03-18 13:37:44 +03:00
}
2016-12-22 21:12:23 +03:00
2014-08-07 01:21:24 +04:00
m . Use ( i18n . I18n ( i18n . Options {
2016-12-22 21:12:23 +03:00
SubURL : setting . AppSubURL ,
Files : localFiles ,
Langs : setting . Langs ,
Names : setting . Names ,
DefaultLang : "en-US" ,
Redirect : true ,
2014-07-26 08:24:27 +04:00
} ) )
2014-08-01 01:25:34 +04:00
m . Use ( cache . Cacher ( cache . Options {
2014-12-31 12:08:57 +03:00
Adapter : setting . CacheAdapter ,
AdapterConfig : setting . CacheConn ,
2016-08-11 15:59:11 +03:00
Interval : setting . CacheInterval ,
2014-08-01 01:25:34 +04:00
} ) )
2014-09-20 04:11:34 +04:00
m . Use ( captcha . Captchaer ( captcha . Options {
2016-11-27 13:14:25 +03:00
SubURL : setting . AppSubURL ,
2014-09-20 04:11:34 +04:00
} ) )
2014-12-28 15:40:35 +03:00
m . Use ( session . Sessioner ( setting . SessionConfig ) )
2014-12-21 06:51:16 +03:00
m . Use ( csrf . Csrfer ( csrf . Options {
2014-09-21 20:22:50 +04:00
Secret : setting . SecretKey ,
2016-03-13 04:56:03 +03:00
Cookie : setting . CSRFCookieName ,
2014-09-21 20:22:50 +04:00
SetCookie : true ,
Header : "X-Csrf-Token" ,
2016-11-27 13:14:25 +03:00
CookiePath : setting . AppSubURL ,
2014-08-01 01:25:34 +04:00
} ) )
2014-08-07 01:21:24 +04:00
m . Use ( toolbox . Toolboxer ( m , toolbox . Options {
HealthCheckFuncs : [ ] * toolbox . HealthCheckFuncDesc {
2016-11-14 19:03:37 +03:00
{
2014-08-07 01:21:24 +04:00
Desc : "Database connection" ,
Func : models . Ping ,
} ,
} ,
} ) )
2016-03-11 19:56:52 +03:00
m . Use ( context . Contexter ( ) )
2014-07-26 08:24:27 +04:00
return m
2014-03-19 13:31:38 +04:00
}
2016-05-12 21:32:28 +03:00
func runWeb ( ctx * cli . Context ) error {
2015-02-05 13:12:37 +03:00
if ctx . IsSet ( "config" ) {
setting . CustomConf = ctx . String ( "config" )
}
2017-01-09 14:54:57 +03:00
if ctx . IsSet ( "pid" ) {
setting . CustomPID = ctx . String ( "pid" )
}
2014-03-30 01:50:51 +04:00
routers . GlobalInit ( )
2014-02-19 13:50:53 +04:00
2014-07-26 08:24:27 +04:00
m := newMacaron ( )
2014-03-15 15:01:50 +04:00
2016-03-11 19:56:52 +03:00
reqSignIn := context . Toggle ( & context . ToggleOptions { SignInRequired : true } )
ignSignIn := context . Toggle ( & context . ToggleOptions { SignInRequired : setting . Service . RequireSignInView } )
ignSignInAndCsrf := context . Toggle ( & context . ToggleOptions { DisableCSRF : true } )
reqSignOut := context . Toggle ( & context . ToggleOptions { SignOutRequired : true } )
2014-03-22 21:44:02 +04:00
2014-05-05 10:42:52 +04:00
bindIgnErr := binding . BindIgnErr
2014-04-10 22:37:43 +04:00
2016-12-30 21:49:54 +03:00
m . Use ( user . GetNotificationCount )
2016-03-06 02:08:42 +03:00
// FIXME: not all routes need go through same middlewares.
// Especially some AJAX requests, we can reduce middleware number to improve performance.
2014-02-19 13:50:53 +04:00
// Routers.
2014-03-24 19:58:46 +04:00
m . Get ( "/" , ignSignIn , routers . Home )
2016-03-11 23:33:12 +03:00
m . Group ( "/explore" , func ( ) {
2016-03-12 01:12:37 +03:00
m . Get ( "" , func ( ctx * context . Context ) {
2016-11-27 13:14:25 +03:00
ctx . Redirect ( setting . AppSubURL + "/explore/repos" )
2016-03-12 01:12:37 +03:00
} )
2016-03-11 23:33:12 +03:00
m . Get ( "/repos" , routers . ExploreRepos )
m . Get ( "/users" , routers . ExploreUsers )
2016-09-01 16:08:05 +03:00
m . Get ( "/organizations" , routers . ExploreOrganizations )
2016-03-11 23:33:12 +03:00
} , ignSignIn )
2015-09-02 23:18:09 +03:00
m . Combo ( "/install" , routers . InstallInit ) . Get ( routers . Install ) .
2015-02-01 20:41:03 +03:00
Post ( bindIgnErr ( auth . InstallForm { } ) , routers . InstallPost )
2015-09-24 21:20:07 +03:00
m . Get ( "/^:type(issues|pulls)$" , reqSignIn , user . Issues )
2014-03-29 18:01:52 +04:00
2015-08-18 21:49:44 +03:00
// ***** START: User *****
2014-10-25 02:43:17 +04:00
m . Group ( "/user" , func ( ) {
m . Get ( "/login" , user . SignIn )
m . Post ( "/login" , bindIgnErr ( auth . SignInForm { } ) , user . SignInPost )
m . Get ( "/sign_up" , user . SignUp )
m . Post ( "/sign_up" , bindIgnErr ( auth . RegisterForm { } ) , user . SignUpPost )
m . Get ( "/reset_password" , user . ResetPasswd )
m . Post ( "/reset_password" , user . ResetPasswdPost )
2017-02-22 10:14:37 +03:00
m . Group ( "/oauth2" , func ( ) {
m . Get ( "/:provider" , user . SignInOAuth )
m . Get ( "/:provider/callback" , user . SignInOAuthCallback )
} )
m . Get ( "/link_account" , user . LinkAccount )
m . Post ( "/link_account_signin" , bindIgnErr ( auth . SignInForm { } ) , user . LinkAccountPostSignIn )
m . Post ( "/link_account_signup" , bindIgnErr ( auth . RegisterForm { } ) , user . LinkAccountPostRegister )
2017-01-16 05:14:29 +03:00
m . Group ( "/two_factor" , func ( ) {
m . Get ( "" , user . TwoFactor )
m . Post ( "" , bindIgnErr ( auth . TwoFactorAuthForm { } ) , user . TwoFactorPost )
m . Get ( "/scratch" , user . TwoFactorScratch )
m . Post ( "/scratch" , bindIgnErr ( auth . TwoFactorScratchAuthForm { } ) , user . TwoFactorScratchPost )
} )
2014-03-23 00:00:46 +04:00
} , reqSignOut )
2015-08-18 21:49:44 +03:00
2014-10-25 02:43:17 +04:00
m . Group ( "/user/settings" , func ( ) {
m . Get ( "" , user . Settings )
m . Post ( "" , bindIgnErr ( auth . UpdateProfileForm { } ) , user . SettingsPost )
2016-08-07 20:27:38 +03:00
m . Combo ( "/avatar" ) . Get ( user . SettingsAvatar ) .
Post ( binding . MultipartForm ( auth . AvatarForm { } ) , user . SettingsAvatarPost )
2016-03-05 08:51:51 +03:00
m . Post ( "/avatar/delete" , user . SettingsDeleteAvatar )
2015-09-10 18:40:34 +03:00
m . Combo ( "/email" ) . Get ( user . SettingsEmails ) .
Post ( bindIgnErr ( auth . AddEmailForm { } ) , user . SettingsEmailPost )
m . Post ( "/email/delete" , user . DeleteEmail )
2014-10-25 02:43:17 +04:00
m . Get ( "/password" , user . SettingsPassword )
m . Post ( "/password" , bindIgnErr ( auth . ChangePasswordForm { } ) , user . SettingsPasswordPost )
2015-08-20 12:11:29 +03:00
m . Combo ( "/ssh" ) . Get ( user . SettingsSSHKeys ) .
Post ( bindIgnErr ( auth . AddSSHKeyForm { } ) , user . SettingsSSHKeysPost )
m . Post ( "/ssh/delete" , user . DeleteSSHKey )
2015-08-18 22:36:16 +03:00
m . Combo ( "/applications" ) . Get ( user . SettingsApplications ) .
Post ( bindIgnErr ( auth . NewAccessTokenForm { } ) , user . SettingsApplicationsPost )
m . Post ( "/applications/delete" , user . SettingsDeleteApplication )
2014-10-25 02:43:17 +04:00
m . Route ( "/delete" , "GET,POST" , user . SettingsDelete )
2017-02-22 10:14:37 +03:00
m . Combo ( "/account_link" ) . Get ( user . SettingsAccountLinks ) . Post ( user . SettingsDeleteAccountLink )
2017-01-16 05:14:29 +03:00
m . Group ( "/two_factor" , func ( ) {
m . Get ( "" , user . SettingsTwoFactor )
m . Post ( "/regenerate_scratch" , user . SettingsTwoFactorRegenerateScratch )
m . Post ( "/disable" , user . SettingsTwoFactorDisable )
m . Get ( "/enroll" , user . SettingsTwoFactorEnroll )
m . Post ( "/enroll" , bindIgnErr ( auth . TwoFactorAuthForm { } ) , user . SettingsTwoFactorEnrollPost )
} )
2016-03-11 19:56:52 +03:00
} , reqSignIn , func ( ctx * context . Context ) {
2015-08-18 21:49:44 +03:00
ctx . Data [ "PageIsUserSettings" ] = true
} )
2014-10-25 02:43:17 +04:00
m . Group ( "/user" , func ( ) {
2014-07-26 08:24:27 +04:00
// r.Get("/feeds", binding.Bind(auth.FeedsForm{}), user.Feeds)
2014-10-25 02:43:17 +04:00
m . Any ( "/activate" , user . Activate )
2014-12-17 18:42:54 +03:00
m . Any ( "/activate_email" , user . ActivateEmail )
2014-10-25 02:43:17 +04:00
m . Get ( "/email2user" , user . Email2User )
m . Get ( "/forget_password" , user . ForgotPasswd )
m . Post ( "/forget_password" , user . ForgotPasswdPost )
m . Get ( "/logout" , user . SignOut )
2014-03-23 00:00:46 +04:00
} )
2015-08-18 21:49:44 +03:00
// ***** END: User *****
2014-03-10 12:54:52 +04:00
2016-03-11 19:56:52 +03:00
adminReq := context . Toggle ( & context . ToggleOptions { SignInRequired : true , AdminRequired : true } )
2014-03-22 21:44:02 +04:00
2015-08-26 16:45:51 +03:00
// ***** START: Admin *****
2014-10-25 02:43:17 +04:00
m . Group ( "/admin" , func ( ) {
2014-08-29 16:50:43 +04:00
m . Get ( "" , adminReq , admin . Dashboard )
2014-10-25 02:43:17 +04:00
m . Get ( "/config" , admin . Config )
2016-02-25 07:59:17 +03:00
m . Post ( "/config/test_mail" , admin . SendTestMail )
2014-10-25 02:43:17 +04:00
m . Get ( "/monitor" , admin . Monitor )
m . Group ( "/users" , func ( ) {
m . Get ( "" , admin . Users )
2016-11-27 09:03:59 +03:00
m . Combo ( "/new" ) . Get ( admin . NewUser ) . Post ( bindIgnErr ( auth . AdminCreateUserForm { } ) , admin . NewUserPost )
2015-12-12 03:24:57 +03:00
m . Combo ( "/:userid" ) . Get ( admin . EditUser ) . Post ( bindIgnErr ( auth . AdminEditUserForm { } ) , admin . EditUserPost )
2014-10-25 02:43:17 +04:00
m . Post ( "/:userid/delete" , admin . DeleteUser )
2014-08-29 16:50:43 +04:00
} )
2014-10-25 02:43:17 +04:00
m . Group ( "/orgs" , func ( ) {
m . Get ( "" , admin . Organizations )
2014-08-29 16:50:43 +04:00
} )
2014-10-25 02:43:17 +04:00
m . Group ( "/repos" , func ( ) {
2015-12-06 01:39:29 +03:00
m . Get ( "" , admin . Repos )
m . Post ( "/delete" , admin . DeleteRepo )
2014-08-29 16:50:43 +04:00
} )
2014-10-25 02:43:17 +04:00
m . Group ( "/auths" , func ( ) {
m . Get ( "" , admin . Authentications )
2015-12-12 03:24:57 +03:00
m . Combo ( "/new" ) . Get ( admin . NewAuthSource ) . Post ( bindIgnErr ( auth . AuthenticationForm { } ) , admin . NewAuthSourcePost )
2015-09-11 19:03:08 +03:00
m . Combo ( "/:authid" ) . Get ( admin . EditAuthSource ) .
Post ( bindIgnErr ( auth . AuthenticationForm { } ) , admin . EditAuthSourcePost )
2014-10-25 02:43:17 +04:00
m . Post ( "/:authid/delete" , admin . DeleteAuthSource )
2014-08-29 16:50:43 +04:00
} )
2014-10-09 02:29:18 +04:00
2014-10-25 02:43:17 +04:00
m . Group ( "/notices" , func ( ) {
m . Get ( "" , admin . Notices )
2015-12-05 09:09:14 +03:00
m . Post ( "/delete" , admin . DeleteNotices )
2015-12-02 07:33:08 +03:00
m . Get ( "/empty" , admin . EmptyNotices )
2014-10-09 02:29:18 +04:00
} )
2014-05-03 06:48:14 +04:00
} , adminReq )
2015-08-26 16:45:51 +03:00
// ***** END: Admin *****
2014-05-03 06:48:14 +04:00
2015-08-11 12:54:00 +03:00
m . Group ( "" , func ( ) {
2015-12-21 15:24:11 +03:00
m . Group ( "/:username" , func ( ) {
m . Get ( "" , user . Profile )
m . Get ( "/followers" , user . Followers )
m . Get ( "/following" , user . Following )
} )
2016-03-11 19:56:52 +03:00
m . Get ( "/attachments/:uuid" , func ( ctx * context . Context ) {
2015-08-11 18:24:40 +03:00
attach , err := models . GetAttachmentByUUID ( ctx . Params ( ":uuid" ) )
if err != nil {
if models . IsErrAttachmentNotExist ( err ) {
ctx . Error ( 404 )
} else {
ctx . Handle ( 500 , "GetAttachmentByUUID" , err )
}
return
}
2015-08-11 23:49:51 +03:00
fr , err := os . Open ( attach . LocalPath ( ) )
if err != nil {
ctx . Handle ( 500 , "Open" , err )
return
}
defer fr . Close ( )
2016-11-26 15:08:31 +03:00
if err = repo . ServeData ( ctx , attach . Name , fr ) ; err != nil {
2015-08-11 23:49:51 +03:00
ctx . Handle ( 500 , "ServeData" , err )
return
}
2015-08-11 18:24:40 +03:00
} )
2017-01-15 17:57:00 +03:00
m . Post ( "/attachments" , repo . UploadAttachment )
2015-08-11 12:54:00 +03:00
} , ignSignIn )
2014-07-12 08:55:19 +04:00
2015-12-21 15:24:11 +03:00
m . Group ( "/:username" , func ( ) {
m . Get ( "/action/:action" , user . Action )
} , reqSignIn )
2014-07-26 08:24:27 +04:00
if macaron . Env == macaron . DEV {
2014-08-01 01:25:34 +04:00
m . Get ( "/template/*" , dev . TemplatePreview )
2014-03-27 19:37:33 +04:00
}
2016-03-11 19:56:52 +03:00
reqRepoAdmin := context . RequireRepoAdmin ( )
reqRepoWriter := context . RequireRepoWriter ( )
2014-07-26 10:28:04 +04:00
2015-08-26 16:45:51 +03:00
// ***** START: Organization *****
2014-10-25 02:43:17 +04:00
m . Group ( "/org" , func ( ) {
2017-02-14 15:16:00 +03:00
m . Group ( "" , func ( ) {
m . Get ( "/create" , org . Create )
m . Post ( "/create" , bindIgnErr ( auth . CreateOrgForm { } ) , org . CreatePost )
} , func ( ctx * context . Context ) {
if ! ctx . User . CanCreateOrganization ( ) {
ctx . NotFound ( )
}
} )
2014-10-25 02:43:17 +04:00
m . Group ( "/:org" , func ( ) {
m . Get ( "/dashboard" , user . Dashboard )
2015-09-24 21:20:07 +03:00
m . Get ( "/^:type(issues|pulls)$" , user . Issues )
2014-10-25 02:43:17 +04:00
m . Get ( "/members" , org . Members )
m . Get ( "/members/action/:action" , org . MembersAction )
m . Get ( "/teams" , org . Teams )
2016-03-11 19:56:52 +03:00
} , context . OrgAssignment ( true ) )
2016-01-31 16:28:42 +03:00
m . Group ( "/:org" , func ( ) {
2014-10-25 02:43:17 +04:00
m . Get ( "/teams/:team" , org . TeamMembers )
m . Get ( "/teams/:team/repositories" , org . TeamRepositories )
2015-11-22 09:32:09 +03:00
m . Route ( "/teams/:team/action/:action" , "GET,POST" , org . TeamsAction )
m . Route ( "/teams/:team/action/repo/:action" , "GET,POST" , org . TeamsRepoAction )
2016-03-11 19:56:52 +03:00
} , context . OrgAssignment ( true , false , true ) )
2014-07-26 10:28:04 +04:00
2014-10-25 02:43:17 +04:00
m . Group ( "/:org" , func ( ) {
m . Get ( "/teams/new" , org . NewTeam )
m . Post ( "/teams/new" , bindIgnErr ( auth . CreateTeamForm { } ) , org . NewTeamPost )
m . Get ( "/teams/:team/edit" , org . EditTeam )
m . Post ( "/teams/:team/edit" , bindIgnErr ( auth . CreateTeamForm { } ) , org . EditTeamPost )
m . Post ( "/teams/:team/delete" , org . DeleteTeam )
m . Group ( "/settings" , func ( ) {
2015-08-26 16:45:51 +03:00
m . Combo ( "" ) . Get ( org . Settings ) .
Post ( bindIgnErr ( auth . UpdateOrgSettingForm { } ) , org . SettingsPost )
2016-08-07 20:27:38 +03:00
m . Post ( "/avatar" , binding . MultipartForm ( auth . AvatarForm { } ) , org . SettingsAvatar )
2016-03-06 19:36:30 +03:00
m . Post ( "/avatar/delete" , org . SettingsDeleteAvatar )
2015-08-26 16:45:51 +03:00
m . Group ( "/hooks" , func ( ) {
m . Get ( "" , org . Webhooks )
m . Post ( "/delete" , org . DeleteWebhook )
2015-08-26 19:30:06 +03:00
m . Get ( "/:type/new" , repo . WebhooksNew )
m . Post ( "/gogs/new" , bindIgnErr ( auth . NewWebhookForm { } ) , repo . WebHooksNewPost )
m . Post ( "/slack/new" , bindIgnErr ( auth . NewSlackHookForm { } ) , repo . SlackHooksNewPost )
2015-08-26 20:04:23 +03:00
m . Get ( "/:id" , repo . WebHooksEdit )
m . Post ( "/gogs/:id" , bindIgnErr ( auth . NewWebhookForm { } ) , repo . WebHooksEditPost )
m . Post ( "/slack/:id" , bindIgnErr ( auth . NewSlackHookForm { } ) , repo . SlackHooksEditPost )
2015-08-26 16:45:51 +03:00
} )
2014-10-25 02:43:17 +04:00
m . Route ( "/delete" , "GET,POST" , org . SettingsDelete )
2014-08-14 10:12:21 +04:00
} )
2014-08-15 14:29:41 +04:00
2014-10-25 02:43:17 +04:00
m . Route ( "/invitations/new" , "GET,POST" , org . Invitation )
2016-03-11 19:56:52 +03:00
} , context . OrgAssignment ( true , true ) )
2014-07-26 10:28:04 +04:00
} , reqSignIn )
2015-08-26 16:45:51 +03:00
// ***** END: Organization *****
2014-07-26 10:28:04 +04:00
2015-08-26 16:45:51 +03:00
// ***** START: Repository *****
2014-10-25 02:43:17 +04:00
m . Group ( "/repo" , func ( ) {
m . Get ( "/create" , repo . Create )
m . Post ( "/create" , bindIgnErr ( auth . CreateRepoForm { } ) , repo . CreatePost )
m . Get ( "/migrate" , repo . Migrate )
m . Post ( "/migrate" , bindIgnErr ( auth . MigrateRepoForm { } ) , repo . MigratePost )
2015-08-08 12:10:34 +03:00
m . Combo ( "/fork/:repoid" ) . Get ( repo . Fork ) .
Post ( bindIgnErr ( auth . CreateRepoForm { } ) , repo . ForkPost )
2014-07-27 07:53:16 +04:00
} , reqSignIn )
2014-10-25 02:43:17 +04:00
m . Group ( "/:username/:reponame" , func ( ) {
m . Group ( "/settings" , func ( ) {
2015-08-26 16:45:51 +03:00
m . Combo ( "" ) . Get ( repo . Settings ) .
Post ( bindIgnErr ( auth . RepoSettingForm { } ) , repo . SettingsPost )
2016-03-06 02:08:42 +03:00
m . Group ( "/collaboration" , func ( ) {
m . Combo ( "" ) . Get ( repo . Collaboration ) . Post ( repo . CollaborationPost )
m . Post ( "/access_mode" , repo . ChangeCollaborationAccessMode )
m . Post ( "/delete" , repo . DeleteCollaboration )
} )
2017-02-21 18:02:10 +03:00
m . Group ( "/branches" , func ( ) {
m . Combo ( "" ) . Get ( repo . ProtectedBranch ) . Post ( repo . ProtectedBranchPost )
m . Post ( "/can_push" , repo . ChangeProtectedBranch )
m . Post ( "/delete" , repo . DeleteProtectedBranch )
} )
2015-08-26 16:45:51 +03:00
m . Group ( "/hooks" , func ( ) {
m . Get ( "" , repo . Webhooks )
m . Post ( "/delete" , repo . DeleteWebhook )
2015-08-26 19:30:06 +03:00
m . Get ( "/:type/new" , repo . WebhooksNew )
m . Post ( "/gogs/new" , bindIgnErr ( auth . NewWebhookForm { } ) , repo . WebHooksNewPost )
m . Post ( "/slack/new" , bindIgnErr ( auth . NewSlackHookForm { } ) , repo . SlackHooksNewPost )
2015-08-26 20:04:23 +03:00
m . Get ( "/:id" , repo . WebHooksEdit )
2015-12-05 21:24:13 +03:00
m . Post ( "/:id/test" , repo . TestWebhook )
2015-08-26 20:04:23 +03:00
m . Post ( "/gogs/:id" , bindIgnErr ( auth . NewWebhookForm { } ) , repo . WebHooksEditPost )
m . Post ( "/slack/:id" , bindIgnErr ( auth . NewSlackHookForm { } ) , repo . SlackHooksEditPost )
m . Group ( "/git" , func ( ) {
m . Get ( "" , repo . GitHooks )
m . Combo ( "/:name" ) . Get ( repo . GitHooksEdit ) .
Post ( repo . GitHooksEditPost )
2016-03-11 19:56:52 +03:00
} , context . GitHookService ( ) )
2015-08-26 16:45:51 +03:00
} )
2015-08-26 19:30:06 +03:00
2015-08-06 17:48:11 +03:00
m . Group ( "/keys" , func ( ) {
2015-08-26 16:45:51 +03:00
m . Combo ( "" ) . Get ( repo . DeployKeys ) .
Post ( bindIgnErr ( auth . AddSSHKeyForm { } ) , repo . DeployKeysPost )
2015-08-06 17:48:11 +03:00
m . Post ( "/delete" , repo . DeleteDeployKey )
} )
2016-03-11 19:56:52 +03:00
} , func ( ctx * context . Context ) {
2015-11-16 19:16:52 +03:00
ctx . Data [ "PageIsSettings" ] = true
2017-02-04 18:53:46 +03:00
} , context . UnitTypes ( ) )
2016-03-11 19:56:52 +03:00
} , reqSignIn , context . RepoAssignment ( ) , reqRepoAdmin , context . RepoRef ( ) )
2014-07-26 10:28:04 +04:00
2016-03-11 19:56:52 +03:00
m . Get ( "/:username/:reponame/action/:action" , reqSignIn , context . RepoAssignment ( ) , repo . Action )
2014-10-25 02:43:17 +04:00
m . Group ( "/:username/:reponame" , func ( ) {
2016-08-09 19:39:55 +03:00
// FIXME: should use different URLs but mostly same logic for comments of issue and pull reuqest.
// So they can apply their own enable/disable logic on routers.
2014-10-25 02:43:17 +04:00
m . Group ( "/issues" , func ( ) {
2016-08-09 19:39:55 +03:00
m . Combo ( "/new" , repo . MustEnableIssues ) . Get ( context . RepoRef ( ) , repo . NewIssue ) .
2015-08-09 10:23:02 +03:00
Post ( bindIgnErr ( auth . CreateIssueForm { } ) , repo . NewIssuePost )
2015-08-13 11:07:11 +03:00
m . Group ( "/:index" , func ( ) {
m . Post ( "/label" , repo . UpdateIssueLabel )
m . Post ( "/milestone" , repo . UpdateIssueMilestone )
2015-08-14 19:42:43 +03:00
m . Post ( "/assignee" , repo . UpdateIssueAssignee )
2016-03-06 04:45:23 +03:00
} , reqRepoWriter )
2015-08-19 23:31:28 +03:00
m . Group ( "/:index" , func ( ) {
m . Post ( "/title" , repo . UpdateIssueTitle )
m . Post ( "/content" , repo . UpdateIssueContent )
2016-08-11 16:22:56 +03:00
m . Combo ( "/comments" ) . Post ( bindIgnErr ( auth . CreateCommentForm { } ) , repo . NewComment )
2015-08-19 23:31:28 +03:00
} )
2016-08-09 19:39:55 +03:00
} )
2016-07-25 21:48:17 +03:00
m . Group ( "/comments/:id" , func ( ) {
m . Post ( "" , repo . UpdateCommentContent )
m . Post ( "/delete" , repo . DeleteComment )
} )
2015-07-24 11:42:47 +03:00
m . Group ( "/labels" , func ( ) {
m . Post ( "/new" , bindIgnErr ( auth . CreateLabelForm { } ) , repo . NewLabel )
m . Post ( "/edit" , bindIgnErr ( auth . CreateLabelForm { } ) , repo . UpdateLabel )
m . Post ( "/delete" , repo . DeleteLabel )
2016-08-30 05:02:49 +03:00
m . Post ( "/initialize" , bindIgnErr ( auth . InitializeLabelsForm { } ) , repo . InitializeLabels )
2016-08-30 15:30:47 +03:00
} , reqRepoWriter , context . RepoRef ( ) )
2015-07-24 11:42:47 +03:00
m . Group ( "/milestones" , func ( ) {
2015-12-03 04:56:26 +03:00
m . Combo ( "/new" ) . Get ( repo . NewMilestone ) .
Post ( bindIgnErr ( auth . CreateMilestoneForm { } ) , repo . NewMilestonePost )
2015-08-06 18:25:35 +03:00
m . Get ( "/:id/edit" , repo . EditMilestone )
m . Post ( "/:id/edit" , bindIgnErr ( auth . CreateMilestoneForm { } ) , repo . EditMilestonePost )
m . Get ( "/:id/:action" , repo . ChangeMilestonStatus )
2015-08-05 15:23:08 +03:00
m . Post ( "/delete" , repo . DeleteMilestone )
2016-08-30 15:30:47 +03:00
} , reqRepoWriter , context . RepoRef ( ) )
2014-12-11 00:37:54 +03:00
m . Group ( "/releases" , func ( ) {
m . Get ( "/new" , repo . NewRelease )
m . Post ( "/new" , bindIgnErr ( auth . NewReleaseForm { } ) , repo . NewReleasePost )
2015-11-20 10:38:41 +03:00
m . Post ( "/delete" , repo . DeleteRelease )
2016-03-11 19:56:52 +03:00
} , reqRepoWriter , context . RepoRef ( ) )
2016-09-03 13:00:59 +03:00
m . Group ( "/releases" , func ( ) {
m . Get ( "/edit/*" , repo . EditRelease )
m . Post ( "/edit/*" , bindIgnErr ( auth . EditReleaseForm { } ) , repo . EditReleasePost )
} , reqRepoWriter , func ( ctx * context . Context ) {
var err error
ctx . Repo . Commit , err = ctx . Repo . GitRepo . GetBranchCommit ( ctx . Repo . Repository . DefaultBranch )
if err != nil {
ctx . Handle ( 500 , "GetBranchCommit" , err )
return
}
ctx . Repo . CommitsCount , err = ctx . Repo . Commit . CommitsCount ( )
if err != nil {
ctx . Handle ( 500 , "CommitsCount" , err )
return
}
ctx . Data [ "CommitsCount" ] = ctx . Repo . CommitsCount
} )
2016-11-05 18:58:53 +03:00
m . Combo ( "/compare/*" , repo . MustAllowPulls , repo . SetEditorconfigIfExists ) .
Get ( repo . CompareAndPullRequest ) .
2015-09-02 02:07:02 +03:00
Post ( bindIgnErr ( auth . CreateIssueForm { } ) , repo . CompareAndPullRequestPost )
2016-08-11 15:48:08 +03:00
m . Group ( "" , func ( ) {
m . Combo ( "/_edit/*" ) . Get ( repo . EditFile ) .
Post ( bindIgnErr ( auth . EditRepoFileForm { } ) , repo . EditFilePost )
m . Combo ( "/_new/*" ) . Get ( repo . NewFile ) .
Post ( bindIgnErr ( auth . EditRepoFileForm { } ) , repo . NewFilePost )
2016-08-15 09:38:35 +03:00
m . Post ( "/_preview/*" , bindIgnErr ( auth . EditPreviewDiffForm { } ) , repo . DiffPreviewPost )
2016-08-28 11:41:44 +03:00
m . Combo ( "/_delete/*" ) . Get ( repo . DeleteFile ) .
Post ( bindIgnErr ( auth . DeleteRepoFileForm { } ) , repo . DeleteFilePost )
2016-08-30 15:07:50 +03:00
m . Group ( "" , func ( ) {
m . Combo ( "/_upload/*" ) . Get ( repo . UploadFile ) .
Post ( bindIgnErr ( auth . UploadRepoFileForm { } ) , repo . UploadFilePost )
m . Post ( "/upload-file" , repo . UploadFileToServer )
m . Post ( "/upload-remove" , bindIgnErr ( auth . RemoveUploadFileForm { } ) , repo . RemoveUploadFileFromServer )
} , func ( ctx * context . Context ) {
if ! setting . Repository . Upload . Enabled {
ctx . Handle ( 404 , "" , nil )
return
}
} )
2016-08-15 09:38:35 +03:00
} , reqRepoWriter , context . RepoRef ( ) , func ( ctx * context . Context ) {
2016-08-28 14:56:41 +03:00
if ! ctx . Repo . Repository . CanEnableEditor ( ) || ctx . Repo . IsViewCommit {
2016-08-15 09:38:35 +03:00
ctx . Handle ( 404 , "" , nil )
return
}
} )
2017-02-04 18:53:46 +03:00
} , reqSignIn , context . RepoAssignment ( ) , repo . MustBeNotBare , context . UnitTypes ( ) )
2014-07-26 10:28:04 +04:00
2014-10-25 02:43:17 +04:00
m . Group ( "/:username/:reponame" , func ( ) {
2015-11-16 18:14:12 +03:00
m . Group ( "" , func ( ) {
m . Get ( "/releases" , repo . Releases )
m . Get ( "/^:type(issues|pulls)$" , repo . RetrieveLabels , repo . Issues )
2015-12-03 22:31:31 +03:00
m . Get ( "/^:type(issues|pulls)$/:index" , repo . ViewIssue )
2015-11-16 18:14:12 +03:00
m . Get ( "/labels/" , repo . RetrieveLabels , repo . Labels )
m . Get ( "/milestones" , repo . Milestones )
2016-03-11 19:56:52 +03:00
} , context . RepoRef ( ) )
2015-11-16 18:14:12 +03:00
2015-11-26 04:10:25 +03:00
// m.Get("/branches", repo.Branches)
2016-12-25 18:27:25 +03:00
m . Post ( "/branches/:name/delete" , reqSignIn , reqRepoWriter , repo . DeleteBranchPost )
2015-11-26 04:10:25 +03:00
m . Group ( "/wiki" , func ( ) {
m . Get ( "/?:page" , repo . Wiki )
2015-11-27 09:50:38 +03:00
m . Get ( "/_pages" , repo . WikiPages )
2015-11-26 04:10:25 +03:00
m . Group ( "" , func ( ) {
2015-11-27 01:33:45 +03:00
m . Combo ( "/_new" ) . Get ( repo . NewWiki ) .
Post ( bindIgnErr ( auth . NewWikiForm { } ) , repo . NewWikiPost )
2015-11-27 09:50:38 +03:00
m . Combo ( "/:page/_edit" ) . Get ( repo . EditWiki ) .
Post ( bindIgnErr ( auth . NewWikiForm { } ) , repo . EditWikiPost )
2016-03-04 21:32:17 +03:00
m . Post ( "/:page/delete" , repo . DeleteWikiPagePost )
2016-03-06 04:45:23 +03:00
} , reqSignIn , reqRepoWriter )
2016-03-11 19:56:52 +03:00
} , repo . MustEnableWiki , context . RepoRef ( ) )
2015-11-26 04:10:25 +03:00
2017-02-14 04:13:59 +03:00
m . Group ( "/wiki" , func ( ) {
m . Get ( "/raw/*" , repo . WikiRaw )
m . Get ( "/*" , repo . WikiRaw )
} , repo . MustEnableWiki )
2014-10-25 02:43:17 +04:00
m . Get ( "/archive/*" , repo . Download )
2014-07-26 08:24:27 +04:00
2015-09-02 11:08:05 +03:00
m . Group ( "/pulls/:index" , func ( ) {
2016-03-11 19:56:52 +03:00
m . Get ( "/commits" , context . RepoRef ( ) , repo . ViewPullCommits )
2016-11-13 05:54:04 +03:00
m . Get ( "/files" , context . RepoRef ( ) , repo . SetEditorconfigIfExists , repo . SetDiffViewStyle , repo . ViewPullFiles )
2016-03-06 04:45:23 +03:00
m . Post ( "/merge" , reqRepoWriter , repo . MergePullRequest )
2016-02-19 22:48:32 +03:00
} , repo . MustAllowPulls )
2015-09-02 11:08:05 +03:00
2014-11-07 06:06:41 +03:00
m . Group ( "" , func ( ) {
2016-11-05 18:58:53 +03:00
m . Get ( "/src/*" , repo . SetEditorconfigIfExists , repo . Home )
2014-11-07 06:06:41 +03:00
m . Get ( "/raw/*" , repo . SingleDownload )
m . Get ( "/commits/*" , repo . RefCommits )
2016-12-29 02:44:32 +03:00
m . Get ( "/graph" , repo . Graph )
2016-11-13 05:54:04 +03:00
m . Get ( "/commit/:sha([a-f0-9]{7,40})$" , repo . SetEditorconfigIfExists , repo . SetDiffViewStyle , repo . Diff )
2015-10-02 11:48:31 +03:00
m . Get ( "/forks" , repo . Forks )
2016-03-11 19:56:52 +03:00
} , context . RepoRef ( ) )
2016-11-03 11:32:55 +03:00
m . Get ( "/commit/:sha([a-f0-9]{7,40})\\.:ext(patch|diff)" , repo . RawDiff )
2014-11-07 22:46:13 +03:00
2016-11-13 05:54:04 +03:00
m . Get ( "/compare/:before([a-z0-9]{40})\\.\\.\\.:after([a-z0-9]{40})" , repo . SetEditorconfigIfExists , repo . SetDiffViewStyle , repo . CompareDiff )
2017-02-04 18:53:46 +03:00
} , ignSignIn , context . RepoAssignment ( ) , repo . MustBeNotBare , context . UnitTypes ( ) )
2016-01-07 06:07:17 +03:00
m . Group ( "/:username/:reponame" , func ( ) {
m . Get ( "/stars" , repo . Stars )
m . Get ( "/watchers" , repo . Watchers )
2017-02-08 17:13:48 +03:00
} , ignSignIn , context . RepoAssignment ( ) , context . RepoRef ( ) , context . UnitTypes ( ) )
2014-03-23 00:00:46 +04:00
2014-10-25 02:43:17 +04:00
m . Group ( "/:username" , func ( ) {
2015-07-31 09:25:12 +03:00
m . Group ( "/:reponame" , func ( ) {
2016-11-05 18:58:53 +03:00
m . Get ( "" , repo . SetEditorconfigIfExists , repo . Home )
m . Get ( "\\.git$" , repo . SetEditorconfigIfExists , repo . Home )
2017-02-04 18:53:46 +03:00
} , ignSignIn , context . RepoAssignment ( true ) , context . RepoRef ( ) , context . UnitTypes ( ) )
2015-07-31 09:25:12 +03:00
2015-08-07 20:04:12 +03:00
m . Group ( "/:reponame" , func ( ) {
2016-12-26 04:16:37 +03:00
m . Group ( "/info/lfs" , func ( ) {
m . Post ( "/objects/batch" , lfs . BatchHandler )
m . Get ( "/objects/:oid/:filename" , lfs . ObjectOidHandler )
m . Any ( "/objects/:oid" , lfs . ObjectOidHandler )
m . Post ( "/objects" , lfs . PostHandler )
} , ignSignInAndCsrf )
2015-10-24 10:36:47 +03:00
m . Any ( "/*" , ignSignInAndCsrf , repo . HTTP )
m . Head ( "/tasks/trigger" , repo . TriggerTask )
2015-08-07 20:04:12 +03:00
} )
2014-09-15 18:09:17 +04:00
} )
2015-08-26 16:45:51 +03:00
// ***** END: Repository *****
2014-03-21 20:48:26 +04:00
2017-01-12 07:27:09 +03:00
m . Group ( "/notifications" , func ( ) {
m . Get ( "" , user . Notifications )
m . Post ( "/status" , user . NotificationStatusPost )
} , reqSignIn )
2016-12-30 21:49:54 +03:00
2016-03-14 01:49:16 +03:00
m . Group ( "/api" , func ( ) {
apiv1 . RegisterRoutes ( m )
} , ignSignIn )
2014-09-22 03:39:10 +04:00
// robots.txt
2016-03-11 19:56:52 +03:00
m . Get ( "/robots.txt" , func ( ctx * context . Context ) {
2014-09-22 03:39:10 +04:00
if setting . HasRobotsTxt {
2015-03-18 08:29:54 +03:00
ctx . ServeFileContent ( path . Join ( setting . CustomPath , "robots.txt" ) )
2014-09-22 03:39:10 +04:00
} else {
ctx . Error ( 404 )
}
} )
2014-03-23 14:27:01 +04:00
// Not found handler.
2014-03-23 09:48:01 +04:00
m . NotFound ( routers . NotFound )
2015-02-01 20:41:03 +03:00
// Flag for port number in case first time run conflict.
if ctx . IsSet ( "port" ) {
2016-11-27 13:14:25 +03:00
setting . AppURL = strings . Replace ( setting . AppURL , setting . HTTPPort , ctx . String ( "port" ) , 1 )
2016-08-12 00:55:10 +03:00
setting . HTTPPort = ctx . String ( "port" )
2015-02-01 20:41:03 +03:00
}
2016-08-12 00:55:10 +03:00
var listenAddr string
2016-11-27 13:14:25 +03:00
if setting . Protocol == setting . UnixSocket {
2016-08-12 00:55:10 +03:00
listenAddr = fmt . Sprintf ( "%s" , setting . HTTPAddr )
} else {
listenAddr = fmt . Sprintf ( "%s:%s" , setting . HTTPAddr , setting . HTTPPort )
2016-08-12 00:46:33 +03:00
}
2016-11-27 13:14:25 +03:00
log . Info ( "Listen: %v://%s%s" , setting . Protocol , listenAddr , setting . AppSubURL )
2016-08-12 00:55:10 +03:00
2016-12-26 04:16:37 +03:00
if setting . LFS . StartServer {
log . Info ( "LFS server enabled" )
}
2017-02-05 16:06:25 +03:00
if setting . EnablePprof {
go func ( ) {
log . Info ( "%v" , http . ListenAndServe ( "localhost:6060" , nil ) )
} ( )
}
2016-08-12 00:55:10 +03:00
var err error
2014-05-26 04:11:25 +04:00
switch setting . Protocol {
case setting . HTTP :
2017-02-22 10:14:37 +03:00
err = runHTTP ( listenAddr , context2 . ClearHandler ( m ) )
2014-05-26 04:11:25 +04:00
case setting . HTTPS :
2017-02-22 10:14:37 +03:00
err = runHTTPS ( listenAddr , setting . CertFile , setting . KeyFile , context2 . ClearHandler ( m ) )
2014-11-04 04:46:53 +03:00
case setting . FCGI :
2017-02-22 10:14:37 +03:00
err = fcgi . Serve ( nil , context2 . ClearHandler ( m ) )
2016-11-27 13:14:25 +03:00
case setting . UnixSocket :
2017-02-05 15:27:37 +03:00
if err := os . Remove ( listenAddr ) ; err != nil && ! os . IsNotExist ( err ) {
2017-01-29 23:13:57 +03:00
log . Fatal ( 4 , "Failed to remove unix socket directory %s: %v" , listenAddr , err )
2016-12-01 02:56:15 +03:00
}
2016-08-12 00:55:10 +03:00
var listener * net . UnixListener
2016-11-04 16:15:55 +03:00
listener , err = net . ListenUnix ( "unix" , & net . UnixAddr { Name : listenAddr , Net : "unix" } )
2016-08-12 00:46:33 +03:00
if err != nil {
2016-08-12 00:55:10 +03:00
break // Handle error after switch
2016-08-12 00:46:33 +03:00
}
2016-08-12 00:55:10 +03:00
// FIXME: add proper implementation of signal capture on all protocols
2016-08-12 00:46:33 +03:00
// execute this on SIGTERM or SIGINT: listener.Close()
2016-08-12 00:55:10 +03:00
if err = os . Chmod ( listenAddr , os . FileMode ( setting . UnixSocketPermission ) ) ; err != nil {
2016-08-12 00:46:33 +03:00
log . Fatal ( 4 , "Failed to set permission of unix socket: %v" , err )
}
2017-02-22 10:14:37 +03:00
err = http . Serve ( listener , context2 . ClearHandler ( m ) )
2014-05-26 04:11:25 +04:00
default :
2014-07-26 08:24:27 +04:00
log . Fatal ( 4 , "Invalid protocol: %s" , setting . Protocol )
2014-05-26 04:11:25 +04:00
}
if err != nil {
2017-01-29 23:13:57 +03:00
log . Fatal ( 4 , "Failed to start server: %v" , err )
2014-03-18 17:58:58 +04:00
}
2016-05-12 21:32:28 +03:00
return nil
2014-02-19 13:50:53 +04:00
}