增加字符编码/HTTP Header管理

This commit is contained in:
GoEdgeLab
2020-09-16 20:29:13 +08:00
parent 12c90bc553
commit b20ab500aa
23 changed files with 827 additions and 50 deletions

View File

@@ -17,18 +17,20 @@ import (
)
type RPCClient struct {
apiConfig *configs.APIConfig
adminClients []pb.AdminServiceClient
nodeClients []pb.NodeServiceClient
nodeGrantClients []pb.NodeGrantServiceClient
nodeClusterClients []pb.NodeClusterServiceClient
nodeIPAddressClients []pb.NodeIPAddressServiceClient
serverClients []pb.ServerServiceClient
apiNodeClients []pb.APINodeServiceClient
originNodeClients []pb.OriginServerServiceClient
httpWebClients []pb.HTTPWebServiceClient
reverseProxyClients []pb.ReverseProxyServiceClient
httpGzipClients []pb.HTTPGzipServiceClient
apiConfig *configs.APIConfig
adminClients []pb.AdminServiceClient
nodeClients []pb.NodeServiceClient
nodeGrantClients []pb.NodeGrantServiceClient
nodeClusterClients []pb.NodeClusterServiceClient
nodeIPAddressClients []pb.NodeIPAddressServiceClient
serverClients []pb.ServerServiceClient
apiNodeClients []pb.APINodeServiceClient
originNodeClients []pb.OriginServerServiceClient
httpWebClients []pb.HTTPWebServiceClient
reverseProxyClients []pb.ReverseProxyServiceClient
httpGzipClients []pb.HTTPGzipServiceClient
httpHeaderPolicyClients []pb.HTTPHeaderPolicyServiceClient
httpHeaderClients []pb.HTTPHeaderServiceClient
}
func NewRPCClient(apiConfig *configs.APIConfig) (*RPCClient, error) {
@@ -47,6 +49,8 @@ func NewRPCClient(apiConfig *configs.APIConfig) (*RPCClient, error) {
httpWebClients := []pb.HTTPWebServiceClient{}
reverseProxyClients := []pb.ReverseProxyServiceClient{}
httpGzipClients := []pb.HTTPGzipServiceClient{}
httpHeaderPolicyClients := []pb.HTTPHeaderPolicyServiceClient{}
httpHeaderClients := []pb.HTTPHeaderServiceClient{}
conns := []*grpc.ClientConn{}
for _, endpoint := range apiConfig.RPC.Endpoints {
@@ -73,21 +77,25 @@ func NewRPCClient(apiConfig *configs.APIConfig) (*RPCClient, error) {
httpWebClients = append(httpWebClients, pb.NewHTTPWebServiceClient(conn))
reverseProxyClients = append(reverseProxyClients, pb.NewReverseProxyServiceClient(conn))
httpGzipClients = append(httpGzipClients, pb.NewHTTPGzipServiceClient(conn))
httpHeaderPolicyClients = append(httpHeaderPolicyClients, pb.NewHTTPHeaderPolicyServiceClient(conn))
httpHeaderClients = append(httpHeaderClients, pb.NewHTTPHeaderServiceClient(conn))
}
return &RPCClient{
apiConfig: apiConfig,
adminClients: adminClients,
nodeClients: nodeClients,
nodeGrantClients: nodeGrantClients,
nodeClusterClients: nodeClusterClients,
nodeIPAddressClients: nodeIPAddressClients,
serverClients: serverClients,
apiNodeClients: apiNodeClients,
originNodeClients: originNodeClients,
httpWebClients: httpWebClients,
reverseProxyClients: reverseProxyClients,
httpGzipClients: httpGzipClients,
apiConfig: apiConfig,
adminClients: adminClients,
nodeClients: nodeClients,
nodeGrantClients: nodeGrantClients,
nodeClusterClients: nodeClusterClients,
nodeIPAddressClients: nodeIPAddressClients,
serverClients: serverClients,
apiNodeClients: apiNodeClients,
originNodeClients: originNodeClients,
httpWebClients: httpWebClients,
reverseProxyClients: reverseProxyClients,
httpGzipClients: httpGzipClients,
httpHeaderPolicyClients: httpHeaderPolicyClients,
httpHeaderClients: httpHeaderClients,
}, nil
}
@@ -168,6 +176,20 @@ func (this *RPCClient) HTTPGzipRPC() pb.HTTPGzipServiceClient {
return nil
}
func (this *RPCClient) HTTPHeaderRPC() pb.HTTPHeaderServiceClient {
if len(this.httpHeaderClients) > 0 {
return this.httpHeaderClients[rands.Int(0, len(this.httpHeaderClients)-1)]
}
return nil
}
func (this *RPCClient) HTTPHeaderPolicyRPC() pb.HTTPHeaderPolicyServiceClient {
if len(this.httpHeaderPolicyClients) > 0 {
return this.httpHeaderPolicyClients[rands.Int(0, len(this.httpHeaderPolicyClients)-1)]
}
return nil
}
func (this *RPCClient) Context(adminId int64) context.Context {
ctx := context.Background()
m := maps.Map{

View File

@@ -1,7 +1,12 @@
package charset
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/configutils"
"github.com/iwind/TeaGo/actions"
)
type IndexAction struct {
@@ -16,7 +21,41 @@ func (this *IndexAction) Init() {
func (this *IndexAction) RunGet(params struct {
ServerId int64
}) {
// TODO
webConfigResp, err := this.RPC().ServerRPC().FindAndInitServerWebConfig(this.AdminContext(), &pb.FindAndInitServerWebRequest{ServerId: params.ServerId})
if err != nil {
this.ErrorPage(err)
return
}
webConfig := &serverconfigs.HTTPWebConfig{}
err = json.Unmarshal(webConfigResp.Config, webConfig)
if err != nil {
this.ErrorPage(err)
return
}
this.Data["webId"] = webConfig.Id
this.Data["charset"] = webConfig.Charset
this.Data["usualCharsets"] = configutils.UsualCharsets
this.Data["allCharsets"] = configutils.AllCharsets
this.Show()
}
func (this *IndexAction) RunPost(params struct {
WebId int64
Charset string
Must *actions.Must
}) {
_, err := this.RPC().HTTPWebRPC().UpdateHTTPWebCharset(this.AdminContext(), &pb.UpdateHTTPWebCharsetRequest{
WebId: params.WebId,
Charset: params.Charset,
})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -12,7 +12,7 @@ func init() {
Helper(helpers.NewUserMustAuth()).
Helper(serverutils.NewServerHelper()).
Prefix("/servers/server/settings/charset").
Get("", new(IndexAction)).
GetPost("", new(IndexAction)).
EndAll()
})
}

View File

@@ -2,9 +2,7 @@ package gzip
import (
"encoding/json"
"errors"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/serverutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/iwind/TeaGo/actions"
@@ -22,32 +20,26 @@ func (this *IndexAction) Init() {
func (this *IndexAction) RunGet(params struct {
ServerId int64
}) {
server, _, isOk := serverutils.FindServer(&this.ParentAction, params.ServerId)
if !isOk {
webConfigResp, err := this.RPC().ServerRPC().FindAndInitServerWebConfig(this.AdminContext(), &pb.FindAndInitServerWebRequest{ServerId: params.ServerId})
if err != nil {
this.ErrorPage(err)
return
}
webConfig := &serverconfigs.HTTPWebConfig{}
err = json.Unmarshal(webConfigResp.Config, webConfig)
if err != nil {
this.ErrorPage(err)
return
}
webId := server.WebId
if webId <= 0 {
resp, err := this.RPC().ServerRPC().InitServerWeb(this.AdminContext(), &pb.InitServerWebRequest{ServerId: params.ServerId})
if err != nil {
this.ErrorPage(err)
return
}
webId = resp.WebId
}
webResp, err := this.RPC().HTTPWebRPC().FindEnabledHTTPWeb(this.AdminContext(), &pb.FindEnabledHTTPWebRequest{WebId: webId})
webResp, err := this.RPC().HTTPWebRPC().FindEnabledHTTPWeb(this.AdminContext(), &pb.FindEnabledHTTPWebRequest{WebId: webConfig.Id})
if err != nil {
this.ErrorPage(err)
return
}
web := webResp.Web
if web == nil {
this.ErrorPage(errors.New("web should not be nil"))
return
}
this.Data["webId"] = web.Id
this.Data["webId"] = webConfig.Id
gzipId := web.GzipId
gzipConfig := &serverconfigs.HTTPGzipConfig{

View File

@@ -0,0 +1,57 @@
package headers
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
"github.com/iwind/TeaGo/actions"
)
type CreateDeletePopupAction struct {
actionutils.ParentAction
}
func (this *CreateDeletePopupAction) Init() {
this.Nav("", "", "")
}
func (this *CreateDeletePopupAction) RunGet(params struct {
HeaderPolicyId int64
}) {
this.Data["headerPolicyId"] = params.HeaderPolicyId
this.Show()
}
func (this *CreateDeletePopupAction) RunPost(params struct {
HeaderPolicyId int64
Name string
Must *actions.Must
}) {
policyConfigResp, err := this.RPC().HTTPHeaderPolicyRPC().FindEnabledHTTPHeaderPolicyConfig(this.AdminContext(), &pb.FindEnabledHTTPHeaderPolicyConfigRequest{HeaderPolicyId: params.HeaderPolicyId})
if err != nil {
this.ErrorPage(err)
return
}
policyConfig := &shared.HTTPHeaderPolicy{}
err = json.Unmarshal(policyConfigResp.Config, policyConfig)
if err != nil {
this.ErrorPage(err)
return
}
deleteHeaders := policyConfig.DeletedHeaders
deleteHeaders = append(deleteHeaders, params.Name)
_, err = this.RPC().HTTPHeaderPolicyRPC().UpdateHTTPHeaderPolicyDeletingHeaders(this.AdminContext(), &pb.UpdateHTTPHeaderPolicyDeletingHeadersRequest{
HeaderPolicyId: params.HeaderPolicyId,
HeaderNames: deleteHeaders,
})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -0,0 +1,86 @@
package headers
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
"github.com/iwind/TeaGo/actions"
)
type CreateSetPopupAction struct {
actionutils.ParentAction
}
func (this *CreateSetPopupAction) Init() {
this.Nav("", "", "")
}
func (this *CreateSetPopupAction) RunGet(params struct {
ServerId int64
HeaderPolicyId int64
}) {
this.Data["headerPolicyId"] = params.HeaderPolicyId
this.Show()
}
func (this *CreateSetPopupAction) RunPost(params struct {
HeaderPolicyId int64
Name string
Value string
Must *actions.Must
}) {
params.Must.
Field("name", params.Name).
Require("请输入Header名称")
configResp, err := this.RPC().HTTPHeaderPolicyRPC().FindEnabledHTTPHeaderPolicyConfig(this.AdminContext(), &pb.FindEnabledHTTPHeaderPolicyConfigRequest{HeaderPolicyId: params.HeaderPolicyId})
if err != nil {
this.ErrorPage(err)
return
}
policyConfig := &shared.HTTPHeaderPolicy{}
err = json.Unmarshal(configResp.Config, policyConfig)
if err != nil {
this.ErrorPage(err)
return
}
// 创建Header
createHeaderResp, err := this.RPC().HTTPHeaderRPC().CreateHTTPHeader(this.AdminContext(), &pb.CreateHTTPHeaderRequest{
Name: params.Name,
Value: params.Value,
})
if err != nil {
this.ErrorPage(err)
return
}
headerId := createHeaderResp.HeaderId
// 保存
policyConfig.SetHeaders = append(policyConfig.SetHeaders, &shared.HTTPHeaderConfig{
Id: headerId,
IsOn: true,
Name: params.Name,
Value: params.Value,
Status: nil,
})
setHeadersJSON, err := json.Marshal(policyConfig.SetHeaders)
if err != nil {
this.ErrorPage(err)
return
}
_, err = this.RPC().HTTPHeaderPolicyRPC().UpdateHTTPHeaderPolicySettingHeaders(this.AdminContext(), &pb.UpdateHTTPHeaderPolicySettingHeadersRequest{
HeaderPolicyId: params.HeaderPolicyId,
HeadersJSON: setHeadersJSON,
})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -0,0 +1,118 @@
package headers
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
)
// 删除Header
type DeleteAction struct {
actionutils.ParentAction
}
func (this *DeleteAction) RunPost(params struct {
HeaderPolicyId int64
Type string
HeaderId int64
}) {
policyConfigResp, err := this.RPC().HTTPHeaderPolicyRPC().FindEnabledHTTPHeaderPolicyConfig(this.AdminContext(), &pb.FindEnabledHTTPHeaderPolicyConfigRequest{
HeaderPolicyId: params.HeaderPolicyId,
})
if err != nil {
this.ErrorPage(err)
return
}
policyConfig := &shared.HTTPHeaderPolicy{}
err = json.Unmarshal(policyConfigResp.Config, policyConfig)
if err != nil {
this.ErrorPage(err)
return
}
switch params.Type {
case "addHeader":
result := []*shared.HTTPHeaderConfig{}
for _, h := range policyConfig.AddHeaders {
if h.Id != params.HeaderId {
result = append(result, h)
}
}
resultJSON, err := json.Marshal(result)
if err != nil {
this.ErrorPage(err)
return
}
_, err = this.RPC().HTTPHeaderPolicyRPC().UpdateHTTPHeaderPolicyAddingHeaders(this.AdminContext(), &pb.UpdateHTTPHeaderPolicyAddingHeadersRequest{
HeaderPolicyId: params.HeaderPolicyId,
HeadersJSON: resultJSON,
})
if err != nil {
this.ErrorPage(err)
return
}
case "setHeader":
result := []*shared.HTTPHeaderConfig{}
for _, h := range policyConfig.SetHeaders {
if h.Id != params.HeaderId {
result = append(result, h)
}
}
resultJSON, err := json.Marshal(result)
if err != nil {
this.ErrorPage(err)
return
}
_, err = this.RPC().HTTPHeaderPolicyRPC().UpdateHTTPHeaderPolicySettingHeaders(this.AdminContext(), &pb.UpdateHTTPHeaderPolicySettingHeadersRequest{
HeaderPolicyId: params.HeaderPolicyId,
HeadersJSON: resultJSON,
})
if err != nil {
this.ErrorPage(err)
return
}
case "replace":
result := []*shared.HTTPHeaderConfig{}
for _, h := range policyConfig.ReplaceHeaders {
if h.Id != params.HeaderId {
result = append(result, h)
}
}
resultJSON, err := json.Marshal(result)
if err != nil {
this.ErrorPage(err)
return
}
_, err = this.RPC().HTTPHeaderPolicyRPC().UpdateHTTPHeaderPolicyReplacingHeaders(this.AdminContext(), &pb.UpdateHTTPHeaderPolicyReplacingHeadersRequest{
HeaderPolicyId: params.HeaderPolicyId,
HeadersJSON: resultJSON,
})
if err != nil {
this.ErrorPage(err)
return
}
case "addTrailer":
result := []*shared.HTTPHeaderConfig{}
for _, h := range policyConfig.AddTrailers {
if h.Id != params.HeaderId {
result = append(result, h)
}
}
resultJSON, err := json.Marshal(result)
if err != nil {
this.ErrorPage(err)
return
}
_, err = this.RPC().HTTPHeaderPolicyRPC().UpdateHTTPHeaderPolicyAddingTrailers(this.AdminContext(), &pb.UpdateHTTPHeaderPolicyAddingTrailersRequest{
HeaderPolicyId: params.HeaderPolicyId,
HeadersJSON: resultJSON,
})
if err != nil {
this.ErrorPage(err)
return
}
}
this.Success()
}

View File

@@ -0,0 +1,48 @@
package headers
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
)
type DeleteDeletingHeaderAction struct {
actionutils.ParentAction
}
func (this *DeleteDeletingHeaderAction) RunPost(params struct {
HeaderPolicyId int64
HeaderName string
}) {
policyConfigResp, err := this.RPC().HTTPHeaderPolicyRPC().FindEnabledHTTPHeaderPolicyConfig(this.AdminContext(), &pb.FindEnabledHTTPHeaderPolicyConfigRequest{HeaderPolicyId: params.HeaderPolicyId})
if err != nil {
this.ErrorPage(err)
return
}
policyConfigJSON := policyConfigResp.Config
policyConfig := &shared.HTTPHeaderPolicy{}
err = json.Unmarshal(policyConfigJSON, policyConfig)
if err != nil {
this.ErrorPage(err)
return
}
headerNames := []string{}
for _, h := range policyConfig.DeletedHeaders {
if h == params.HeaderName {
continue
}
headerNames = append(headerNames, h)
}
_, err = this.RPC().HTTPHeaderPolicyRPC().UpdateHTTPHeaderPolicyDeletingHeaders(this.AdminContext(), &pb.UpdateHTTPHeaderPolicyDeletingHeadersRequest{
HeaderPolicyId: params.HeaderPolicyId,
HeaderNames: headerNames,
})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -1,7 +1,11 @@
package headers
import (
"encoding/json"
"errors"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
)
type IndexAction struct {
@@ -16,7 +20,73 @@ func (this *IndexAction) Init() {
func (this *IndexAction) RunGet(params struct {
ServerId int64
}) {
// TODO
webConfigResp, err := this.RPC().ServerRPC().FindAndInitServerWebConfig(this.AdminContext(), &pb.FindAndInitServerWebRequest{ServerId: params.ServerId})
if err != nil {
this.ErrorPage(err)
return
}
webConfig := &serverconfigs.HTTPWebConfig{}
err = json.Unmarshal(webConfigResp.Config, webConfig)
if err != nil {
this.ErrorPage(err)
return
}
// 初始化Header
webResp, err := this.RPC().HTTPWebRPC().FindEnabledHTTPWeb(this.AdminContext(), &pb.FindEnabledHTTPWebRequest{WebId: webConfig.Id})
if err != nil {
this.ErrorPage(err)
return
}
web := webResp.Web
if web == nil {
this.ErrorPage(errors.New("web should not be nil"))
return
}
isChanged := false
if web.RequestHeaderPolicyId <= 0 {
createHeaderPolicyResp, err := this.RPC().HTTPHeaderPolicyRPC().CreateHTTPHeaderPolicy(this.AdminContext(), &pb.CreateHTTPHeaderPolicyRequest{})
if err != nil {
this.ErrorPage(err)
return
}
headerPolicyId := createHeaderPolicyResp.HeaderPolicyId
_, err = this.RPC().HTTPWebRPC().UpdateHTTPWebRequestHeaderPolicy(this.AdminContext(), &pb.UpdateHTTPWebRequestHeaderPolicyRequest{
WebId: web.Id,
HeaderPolicyId: headerPolicyId,
})
isChanged = true
}
if web.ResponseHeaderPolicyId <= 0 {
createHeaderPolicyResp, err := this.RPC().HTTPHeaderPolicyRPC().CreateHTTPHeaderPolicy(this.AdminContext(), &pb.CreateHTTPHeaderPolicyRequest{})
if err != nil {
this.ErrorPage(err)
return
}
headerPolicyId := createHeaderPolicyResp.HeaderPolicyId
_, err = this.RPC().HTTPWebRPC().UpdateHTTPWebResponseHeaderPolicy(this.AdminContext(), &pb.UpdateHTTPWebResponseHeaderPolicyRequest{
WebId: web.Id,
HeaderPolicyId: headerPolicyId,
})
isChanged = true
}
// 重新获取配置
if isChanged {
webConfigResp, err := this.RPC().ServerRPC().FindAndInitServerWebConfig(this.AdminContext(), &pb.FindAndInitServerWebRequest{ServerId: params.ServerId})
if err != nil {
this.ErrorPage(err)
return
}
err = json.Unmarshal(webConfigResp.Config, webConfig)
if err != nil {
this.ErrorPage(err)
return
}
}
this.Data["requestHeaderPolicy"] = webConfig.RequestHeaders
this.Data["responseHeaderPolicy"] = webConfig.ResponseHeaders
this.Show()
}

View File

@@ -13,6 +13,11 @@ func init() {
Helper(serverutils.NewServerHelper()).
Prefix("/servers/server/settings/headers").
Get("", new(IndexAction)).
GetPost("/createSetPopup", new(CreateSetPopupAction)).
GetPost("/updateSetPopup", new(UpdateSetPopupAction)).
GetPost("/createDeletePopup", new(CreateDeletePopupAction)).
Post("/deleteDeletingHeader", new(DeleteDeletingHeaderAction)).
Post("/delete", new(DeleteAction)).
EndAll()
})
}

View File

@@ -0,0 +1,63 @@
package headers
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
"github.com/iwind/TeaGo/actions"
)
type UpdateSetPopupAction struct {
actionutils.ParentAction
}
func (this *UpdateSetPopupAction) Init() {
this.Nav("", "", "")
}
func (this *UpdateSetPopupAction) RunGet(params struct {
HeaderPolicyId int64
HeaderId int64
}) {
this.Data["headerPolicyId"] = params.HeaderPolicyId
this.Data["headerId"] = params.HeaderId
headerResp, err := this.RPC().HTTPHeaderRPC().FindEnabledHTTPHeaderConfig(this.AdminContext(), &pb.FindEnabledHTTPHeaderConfigRequest{HeaderId: params.HeaderId})
if err != nil {
this.ErrorPage(err)
return
}
headerConfig := &shared.HTTPHeaderConfig{}
err = json.Unmarshal(headerResp.Config, headerConfig)
if err != nil {
this.ErrorPage(err)
return
}
this.Data["headerConfig"] = headerConfig
this.Show()
}
func (this *UpdateSetPopupAction) RunPost(params struct {
HeaderId int64
Name string
Value string
Must *actions.Must
}) {
params.Must.
Field("name", params.Name).
Require("请输入Header名称")
_, err := this.RPC().HTTPHeaderRPC().UpdateHTTPHeader(this.AdminContext(), &pb.UpdateHTTPHeaderRequest{
HeaderId: params.HeaderId,
Name: params.Name,
Value: params.Value,
})
if err != nil {
this.ErrorPage(err)
}
this.Success()
}

View File

@@ -201,7 +201,7 @@ func (this *ServerHelper) createSettingsMenu(secondMenuItem string, serverIdStri
})
menuItems = append(menuItems, maps.Map{
"name": "字符",
"name": "字符编码",
"url": "/servers/server/settings/charset?serverId=" + serverIdString,
"isActive": secondMenuItem == "charset",
})