I just started to get into golang and as I plan to host at least two websites, I chose to use Mux to display different routes by "filtering" domains. Whenever I try to access my main route, it just gives me an 404 error. (Also, the fact that the "www" part is absent is perfectly normal. I don't type that to access the site).
But if I launch the server as a file server, I can access my files, so the server in itself is working I guess
func redirect(w http.ResponseWriter, req *http.Request) {
target := "https://" + req.Host + req.URL.Path
http.Redirect(w, req, target,
http.StatusTemporaryRedirect)
}
func main() {
go http.ListenAndServe(":80", http.HandlerFunc(redirect)) // Redirection
// Serveur sécurisé
r := mux.NewRouter()
r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir("/root/go/src/web/static/"))))
s := r.Host("echecderi.me").Subrouter()
s.HandleFunc("/", indexEchec)
http.ListenAndServeTLS(":443", "domain-crt.pem", "domain-key.pem", nil)
}
func indexEchec(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "<h1>Echec de rime</h1> </br> <img src=\"/static/echecderime/echec.gif\">")
}
I think you need to give r as the last parameter to http.ListenAndServeTLS.
you can also use a http.server instance
//create server instance
server := http.Server{
Addr: ":443",
TLSConfig: tlsConfig(cert),
}
rtr := mux.NewRouter()
rtr.HandleFunc("/profile", HandlerProfile).Methods("GET")
//rtr.HandleFunc( other routes...
//pass mux handler to server
server.Handler = rtr
server.ListenAndServeTLS("", "")
Related
I'm trying to build a web application with the following stack:
Flutter/Dart
Go/goproxy
gRPC
MongoDB
I was able to successfully define and compile a protobuf into Dart and Go, however now that I'm trying to integrate the UI with the backend, I am running into the following issue:
Error: gRPC Error (code: 2, codeName: UNKNOWN, message:
null, details: [], rawResponse: null, trailers: {})
Here is my client code:
import 'package:grpc/grpc_web.dart';
import 'package:proj/protos/cards.pb.dart';
import 'package:proj/protos/cards.pbgrpc.dart';
class FiltersService {
static ResponseFuture<Filters> getFilters() {
GrpcWebClientChannel channel =
GrpcWebClientChannel.xhr(Uri.parse('http://localhost:9000'));
FiltersServiceClient clientStub = FiltersServiceClient(
channel,
);
return clientStub.getFilters(Void());
}
}
The server controller code:
const (
port = 9000
)
var (
grpcServer *grpc.Server
)
func StartServer() {
log.Println("Starting server")
listener, err := net.Listen("tcp", fmt.Sprintf(":%v", port))
if err != nil {
log.Fatalf("Unable to listen to port %v\n%v\n", port, err)
}
repositories.ConnectToMongoDB()
grpcServer = grpc.NewServer()
registerServices()
grpcWebServer := grpcweb.WrapServer(grpcServer)
httpServer := &http.Server{
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.ProtoMajor == 2 {
grpcWebServer.ServeHTTP(w, r)
} else {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
w.Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, X-User-Agent, X-Grpc-Web")
w.Header().Set("grpc-status", "")
w.Header().Set("grpc-message", "")
if grpcWebServer.IsGrpcWebRequest(r) {
grpcWebServer.ServeHTTP(w, r)
}
}
}),
}
httpServer.Serve(listener)
}
// Register services defined in protobufs to call from UI
func registerServices() {
cardsService := &services.CardsService{}
protos.RegisterCardsServiceServer(grpcServer, cardsService)
filtersService := &services.FiltersService{}
protos.RegisterFiltersServiceServer(grpcServer, filtersService)
}
I can tell that the server is receiving the request properly, and when I output the response of the service, I am getting the expected response.
Here is the service I am calling:
func (service *FiltersService) GetFilters(ctx context.Context, void *protos.Void) (*protos.Filters, error) {
filters := repositories.GetFilters()
return converters.FiltersStructToFiltersProtoConverter(filters), nil
}
When I output the response of converters.FiltersStructToFiltersProtoConverter(filters), I get the correct output, so it looks like there's still an issue with the way my server is set up.
I know this isn't a lot of info to go on, however I'm not sure what other information you may need, but can add as needed.
Curently i'm building an Azure serverless Function in GoLang. I must have a swagger specification inside the function.
I'm using gin as http framework and swaggo as the swagger specification generator.
Main function:
func main() {
port, exists := os.LookupEnv("FUNCTIONS_CUSTOMHANDLER_PORT")
if !exists {
port = "8080"
}
r := gin.Default()
v1 := r.Group("/api")
v1.GET("/ping", function.Ping)
v1.GET("/docs", function.Swagger)
url := ginSwagger.URL("http://localhost:7071/api/docs")
v1.GET("/swagger", ginSwagger.WrapHandler(swaggerFiles.Handler, url))
r.Run(":" + port)
}
The function that will return the swagger.json:
func Swagger(c *gin.Context) {
c.File("docs/swagger.json")
}
When we build the application and run it local the response is 404.
I use go-daemon library to fork process and run it in background. And I need to restart the daemon process after update performed from within http handler.
The handler code is
func httpUpdate(w http.ResponseWriter, req *http.Request) {
if !isPost(req.Method) {
http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
return
}
if checkAuth(req) != 200 {
http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
return
}
log.Println("INFO: Update request, checking for update...")
var err = doUpdate(UPDATE_URL, nil, false)
if !isError(err) {
log.Println("INFO: Update successful, exit")
var system = RealSystem{}
system.Run(fmt.Sprintf("(sleep 0.3s && %s start &> /test/extra.log)&disown", appFilename()))
system.Exit(0)
return
}
w.WriteHeader(http.StatusNoContent)
}
doUpdate() returns nil if successfully replaced the executable file. RealSystem is just wrapper for exec.Command and os.Exit(). appFilename() is the executable file name. The command to start app is /path/to/app start.
I see that new process starts, but executing Context::Reborn() fails with EOF error. Looks like some intrinsic pipes used as implementation details fail with EOF (may be...).
What would be the reason? Or may be there is a better way of doing that?
For now everything happens inside docker container in the "context" of e2e test if it matters. I spent hours trying to make it work but with no success.
I assume you mean restarting the currently running Go binary. You can use a syscall for unix-based systems, and use an exec.Command for Windows.
func RestartSelf() error {
self, err := osext.Executable()
if err != nil {
return err
}
args := os.Args
env := os.Environ()
// Windows does not support exec syscall.
if runtime.GOOS == "windows" {
cmd := exec.Command(self, args[1:]...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Stdin = os.Stdin
cmd.Env = env
err := cmd.Run()
if err == nil {
os.Exit(0)
}
return err
}
return syscall.Exec(self, args, env)
}
The issue is specific to the library. Spawn new self instance from within child process is not a problem for the system, but for that library.
To achieve this it's necessary to execute something like that.
Note the _GO_DAEMON=0 variable set to zero. This makes library follow parent control flow.
var cmd = exec.Command("bash", "-c", fmt.Sprintf("sleep 0.5s; _GO_DAEMON=0 %s start", appFilename()))
var err = cmd.Start()
Also it was necessary to make small changes to the original library. Here is the fork.
I'm using Go with command to execute curl which works as expected
curl := exec.Command("curl", "https://services.odata.org/V3/northwind/northwind.svc/")
out, err := curl.Output()
if err != nil {
fmt.Println("erorr" , err)
return
}
fmt.Println(out)
Now I want to use some placeholders like
curl -O http://quiet-waters-1228.herokuapp.com/assets/image.jpg
but now I need to get the url for command
e.g. if I run in bash mytool url I got the url value
`curl -O $(mytool url)`
The problem is that we need to execute the command in the code and I'm not sure how to pass it
curl := exec.Command("curl", "curl -O $(url)")
out, err := curl.Output()
if err != nil {
fmt.Println("erorr" , err)
return
}
fmt.Println(out)
In os package you have slice of strings which contains all arguments passed by shell to your program.
os.Args 0th value, i.e., first element is going to be name of the command itself.
If your tool command is mytool, os.Args[0] contains mytool.
Rest are going to be the arguments, which are passed by shell.
package main
import (
"log"
"os"
"os/exec"
)
func main() {
if len(os.Args) < 2 {
// If argument is not provided quit
log.Fatalln("url not provided")
}
url := os.Args[1] // URL
cmd := exec.Command("curl", "-O", url)
cmd.Run()
}
You can also download multiple URLs concurrently,
var wg *sync.WaitGroup
func main() {
urls := os.Args[1:]
wg = new(sync.WaitGroup)
wg.Add(len(urls))
for _, url := range urls {
go download(url)
}
wg.Wait()
}
func download(url string) {
defer wg.Done()
cmd := exec.Command("curl", "-O", url)
cmd.Run()
}
I was implementing a simple web server in Go. As I have no experience in web development, this striked as a serious question for me.
Let's say I'm serving web pages with a modified loadPage function from here
func loadPage(title string) []byte {
filename := title
body, _ := ioutil.ReadFile(filename)
return body
}
func handler(w http.ResponseWriter, req *http.Request) {
content := loadPage(req.URL.Path[1:])
fmt.Fprintf(w, "%s", content)
}
Technically this allows me to write a request in a form of
http://example.com/../../etc/passwd
and the code would happily serve the /etc/passwd file, but it does not. Does this mean that there is some sort of protection against ../ in the Go http package or http protocol itself, or am I just doing something wrong and it is a security hole?
net/http does this in its HTTP request multiplexer, ServeMux:
ServeMux also takes care of sanitizing the URL request path, redirecting any request containing . or .. elements to an equivalent .- and ..-free URL.
The relevant function is the private func cleanPath(p string) string, which calls path.Clean:
1415 np := path.Clean(p)
path.Clean does the appropriate removals:
97 case path[r] == '.' && path[r+1] == '.' && (r+2 == n || path[r+2] == '/'):
98 // .. element: remove to last /
99 r += 2
100 switch {
101 case out.w > dotdot:
102 // can backtrack
103 out.w--
104 for out.w > dotdot && out.index(out.w) != '/' {
105 out.w--
106 }
There's an additional case if the path isn't rooted, but cleanPath above ensures it is so, by prepending a forward-slash to the path to be cleaned if there isn't one already.