file upload with HTTP/JSON to gRPC Transcoding - rest

in this page it is described how to automatically support REST requests in an existing GRPC server
https://cloud.google.com/endpoints/docs/grpc/transcoding
But there is no mention for file upload support . For example is it possible to support requests such as this
curl -F "image=#/home/user1/Desktop/test.jpg" localhost/uploader.php
with this or similar methods ?
The grpc code handles files in this way :
Proto files:
service serviceName {
...
rpc WriteApi(TarFile) returns (Status) { }
...
}
message TarFile {
bytes contents = 1;
string somethingElse =2;
}
and in the serving function something like :
func (server *Server) WriteApi(ctx context.Context, jf1 *pb.TarFile) (*pb.Status, error) {
buf1 := bytes.NewBuffer(jf1.Contents)
tr1 := tar.NewReader(buf1)
for {
hdr1, err1 := tr1.Next()
if err1 == io.EOF {
break
}
if err1 != nil {
log.Fatal(err1)
}
bud1 := new(bytes.Buffer)
bud1.ReadFrom(tr1)
s1 := bud1.String()
l4g.Info(s1)
ioutil.WriteFile(rseedstr+"/"+hdr1.Name, []byte(s1), 0644)
}

Related

Execute powershell command in running container via Docker API

I want to execute a powershell command in a docker container running on a windows host.
The specific command I want to execute is "powershell Get-PSDrive C | Select-Object Used,Free"
I have implemented this using the Docker API for python and it is simple like calling:
cmd = "powershell Get-PSDrive C | Select-Object Used,Free"
output = container.exec_run(cmd)
This works as intended, but I need to implement this in golang.
But somehow, it is not clear for me how to interact with the Docker API for golang. I looked into the API and was confused by the hijackedSession. How do I have to setup the calls for ContainerExecCreate, ContainerExecAttach and ContainerExecStart ?
I expect the golang script to deliver the same results like the python code does:
Used Free
---- ----
199181606912 307151622144
Which then can be parsed by me.
The HijackedResponse struct:
type HijackedResponse struct {
Conn net.Conn
Reader *bufio.Reader
}
You need to copy the response from the resp.Reader,here is my code:
package main
import (
"bytes"
"context"
"fmt"
"github.com/docker/docker/api/types"
"github.com/docker/docker/client"
"github.com/docker/docker/pkg/stdcopy"
"strings"
)
func readFromCommand() (string, error) {
cli, err := client.NewEnvClient()
if err != nil {
return "", err
}
ctx := context.Background()
config := types.ExecConfig{
Cmd: strings.Split("powershell Get-PSDrive C | Select-Object Used,Free", " "),
AttachStdout: true,
AttachStderr: true,
}
response, err := cli.ContainerExecCreate(ctx,
// container id
"cf59d65ab1", config)
if err != nil {
return "", err
}
execID := response.ID
resp, err := cli.ContainerExecAttach(ctx, execID, config)
if err != nil {
return "", err
}
defer resp.Close()
stdout := new(bytes.Buffer)
stderr := new(bytes.Buffer)
_, err = stdcopy.StdCopy(stdout, stderr, resp.Reader)
if err != nil {
return "", err
}
s := stdout.String()
fmt.Println(s)
i := stderr.String()
fmt.Println(i)
return s, nil
}
Do remember to change the container id.

SSL Socket client in Golang

I'm trying to connect to a server through a socket using an ssl certificate. I have the private key and the certificate needed to connect to the server, i have looked around for something to help me write this code in Go but i have not found anything helpful. Here is the code i write so far, but it does not seem to get me anywhere, it seems to be sending data(tls.dial) before getting to the actual data, which forces the server to reply with some encrypted data which i am unable to check.
func main() {
cert, err := tls.LoadX509KeyPair("cert.pem", "key.pem")
if err != nil {
log.Fatalf("server: loadkeys: %s", err)
}
config := tls.Config{Certificates: []tls.Certificate{cert}, InsecureSkipVerify: true}
conn, err := tls.Dial("tcp", "1.2.3.4:1234", &config)
if err != nil {
log.Fatalf("client: dial: %s", err)
}
defer conn.Close()
log.Println("client: connected to: ", conn.RemoteAddr())
state := conn.ConnectionState()
for _, v := range state.PeerCertificates {
fmt.Println(x509.MarshalPKIXPublicKey(v.PublicKey))
fmt.Println(v.Subject)
}
log.Println("client: handshake: ", state.HandshakeComplete)
log.Println("client: mutual: ", state.NegotiatedProtocolIsMutual)
message := "data"
n, err := io.WriteString(conn, message)
if err != nil {
log.Fatalf("client: write: %s", err)
}
log.Printf("client: wrote %q (%d bytes)", message, n)
reply := make([]byte, 256)
n, err = conn.Read(reply)
log.Printf("client: read %q (%d bytes)", string(reply[:n]), n)
log.Print("client: exiting")
}

socket programming, getting getsockopt: connection refused

I'm having trouble with socket programming.
I have a program that reads from localhost:7777 and writes to localhost:8000.
I use netcat from the command line to write and read to 7777 and 8000 respectively.
This is the reader:
netcat -l -p 8000
And this is the writer:
printf "asti||" | netcat localhost 7777
But my program gets network errors when it tries to write to port 8000 for the second
time. The error is Fatal error: dial tcp 127.0.0.1:8000: getsockopt: connection refused.
What's happening? Why on the second write the error appears?
Furthermore, I noticed that if I kill the netcat reader and restart it then there's no network errors. So to reiterate, the program writes once to 8000 and netcat reads it. Then I kill netcat reader and restart it. At this point the program can write again to 8000. But if the program tries to write two successive times to 8000 without me restarting netcat, then the error appears.
Here is the entire program (it's short). If you like, you experience this mystical behaviour yourself:
package main
import (
"fmt"
"net"
"os"
"strings"
// "io/ioutil"
)
func main() {
end_of_message_terminator := "||"
beginning_of_next_message := ""
request := make([]byte, 512)
service_port := ":7777"
tcpAddr, err := net.ResolveTCPAddr("tcp4", service_port)
checkError(err)
listener, err := net.ListenTCP("tcp", tcpAddr)
checkError(err)
for {
conn, err := listener.Accept()
if err != nil {
continue
}
read_len, err := conn.Read(request)
if read_len == 0 {
continue
}
request_string := string(request[:read_len])
fmt.Printf("Request String %s\\END", request_string)
messages := strings.Split(request_string, end_of_message_terminator)
fmt.Printf("%q\n", messages)
messages[0] = beginning_of_next_message + messages[0]
if messages[len(messages) - 1] != "" {
beginning_of_next_message = messages[len(messages) - 1]
messages[len(messages) - 1] = ""
fmt.Printf("was here 00\n")
}
if len(messages) == 1 {
continue
}
for i := range messages {
go func(){
fmt.Printf("was here 04\n")
respond_to_message(messages[i])
}()
fmt.Printf("was here 01\n")
}
conn.Close()
}
}
func respond_to_message(message string){
message_parameters := strings.Split(message, "|")
response_port := "localhost:8000"
tcpAddr_res, err := net.ResolveTCPAddr("tcp4", response_port)
checkError(err)
response_writer, err := net.DialTCP("tcp", nil, tcpAddr_res)
for i := range message_parameters {
fmt.Printf("was here03\n")
param_parts := strings.Split(message_parameters[i], "=")
fmt.Printf("message: %s\n", message)
fmt.Printf("message_parameters%q\n", message_parameters)
fmt.Printf("params_parts: %q\n", param_parts)
//param_name := param_parts[0]
//param_value := param_parts[1]
checkError(err)
response_writer.Write([]byte("asti de crhis"))
checkError(err)
//result, err := ioutil.ReadAll(response_writer)
//checkError(err)
//fmt.Println(string(result))
}
//response_writer.Close()
}
func checkError(err error) {
if err != nil {
fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error())
os.Exit(1)
}
}

Go HTTP Request with Basic Auth returning a 401 instead of a 301 redirect

Using Go 1.5.1.
When I try to make a request to a site that automatically redirects to HTTPS using Basic Auth I would expect to get a 301 Redirect response, instead I get a 401.
package main
import "net/http"
import "log"
func main() {
url := "http://aerolith.org/files"
username := "cesar"
password := "password"
req, err := http.NewRequest("GET", url, nil)
if err != nil {
log.Println("error", err)
}
if username != "" || password != "" {
req.SetBasicAuth(username, password)
log.Println("[DEBUG] Set basic auth to", username, password)
}
cli := &http.Client{
}
resp, err := cli.Do(req)
if err != nil {
log.Println("Do error", err)
}
log.Println("[DEBUG] resp.Header", resp.Header)
log.Println("[DEBUG] req.Header", req.Header)
log.Println("[DEBUG] code", resp.StatusCode)
}
Note that curl returns a 301:
curl -vvv http://aerolith.org/files --user cesar:password
Any idea what could be going wrong?
A request to http://aerolith.org/files redirects to https://aerolith.org/files (note change from http to https). A request to https://aerolith.org/files redirects to https://aerolith.org/files/ (note addition of trailing /).
Curl does not follow redirects. Curl prints the 301 status for the redirect from http://aerolith.org/files to https://aerolith.org/files/.
The Go client follows the two redirects to https://aerolith.org/files/. The request to https://aerolith.org/files/ returns with status 401 because the Go client does not propagate the authorization header through the redirects.
Requests to https://aerolith.org/files/ from the Go client and Curl return status 200.
If you want to follow the redirects and auth successfully, set auth header in a CheckRedirect function:
cli := &http.Client{
CheckRedirect: func(req *http.Request, via []*http.Request) error {
if len(via) >= 10 {
return errors.New("stopped after 10 redirects")
}
req.SetBasicAuth(username, password)
return nil
}}
resp, err := cli.Do(req)
If you want to match what Curl does, use a transport directly. The transport does not follow redirects.
resp, err := http.DefaultTransport.RoundTrip(req)
The application can also use the client CheckRedirect function and a distinguished error to prevent redirects as shown in an answer to How Can I Make the Go HTTP Client NOT Follow Redirects Automatically?. This technique seems to be somewhat popular, but is more complicated than using the transport directly.
redirectAttemptedError := errors.New("redirect")
cli := &http.Client{
CheckRedirect: func(req *http.Request, via []*http.Request) error {
return redirectAttemptedError
}}
resp, err := cli.Do(req)
if urlError, ok := err.(*url.Error); ok && urlError.Err == redirectAttemptedError {
// ignore error from check redirect
err = nil
}
if err != nil {
log.Println("Do error", err)
}

Trouble reading from a socket in go

I'm trying to learn the go language, and I'm writing a simple echo server. I'm having difficulty making it work, though.
func listen(server string) {
var buf []byte
listener, ok := net.Listen("tcp", server)
if ok != nil {
fmt.Fprintf(os.Stderr, "Could not listen on socket: %s\n", ok.String())
return
}
conn, ok := listener.Accept()
if ok != nil {
fmt.Fprintf(os.Stderr, "Could not accept connection on socket: %s\n", ok.String())
return
}
writelen, ok := conn.Write(strings.Bytes("Ready to receive\n"))
if ok != nil {
fmt.Fprintf(os.Stderr, "Could not write to socket: %s\n", ok.String())
} else {
fmt.Printf("Wrote %d bytes to socket\n", writelen)
}
for ;; {
readlen, ok := conn.Read(buf)
if ok != nil {
fmt.Fprintf(os.Stderr, "Error when reading from socket: %s\n", ok.String())
return
}
if readlen == 0 {
fmt.Printf("Connection closed by remote host\n")
return
}
fmt.Printf("Client at %s says '%s'\n", conn.RemoteAddr().String(), buf)
}
}
I get the following output from this function:
[nathan#ebisu ~/src/go/echo_server] ./6.out 1234
Using port 1234
Wrote 17 bytes to socket
Error when reading from socket: EOF
This is what I see on the client:
[nathan#ebisu ~] telnet 127.0.0.1 1234
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
Ready to receive
Connection closed by foreign host.
Any help would be appreciated (or pointers to resources; the go documentation on the sockets API leaves a little to be desired).
Thanks,
Nathan
In your example, buf needs to have a definite size. You've declared it as a 0-length slice.
Declare it as:
var buf = make([]byte, 1024)
Of course, if you want to learn, it is better to write it yourself but, if it helps, here is my own echo server in Go.
package main
import (
"net";
"os";
"fmt";
)
func handle(conn *net.TCPConn) {
fmt.Printf("Connection from %s\n", conn.RemoteAddr());
message := make([]byte, 1024);
// TODO: loop the read, we can have >1024 bytes
n1, error := conn.Read(message);
if error != nil {
fmt.Printf("Cannot read: %s\n", error);
os.Exit(1);
}
n2, error := conn.Write(message[0:n1]);
if error != nil || n2 != n1 {
fmt.Printf("Cannot write: %s\n", error);
os.Exit(1);
}
fmt.Printf("Echoed %d bytes\n", n2);
conn.Close(); // TODO: wait to see if more data? It would be better with telnet...
}
func main() {
listen := ":7";
addr, error := net.ResolveTCPAddr(listen);
if error != nil {
fmt.Printf("Cannot parse \"%s\": %s\n", listen, error);
os.Exit(1);
}
listener, error := net.ListenTCP("tcp", addr);
if error != nil {
fmt.Printf("Cannot listen: %s\n", error);
os.Exit(1);
}
for { // ever...
conn, error := listener.AcceptTCP();
if error != nil {
fmt.Printf("Cannot accept: %s\n", error);
os.Exit(1);
}
go handle(conn);
}
}