February 26, 2015, 11:50 pm
I was asked this in an interview a few years back and I though it was kind of neat. The question is how do you select a single line from a file randomly, such that each line has a equal probability of being selected. The naive solution is of course to count the number of lines in the file, and then to select a line and get it from the file. But can you do it in a single pass, without seeking through the file?
The solution is kind of neat, have a buffer to store a “selected” line from the file. Then you read each line in turn, you then randomly swap your “selected” line with the new line with decreasing probability. The probability decreases to compensate for the fact that previous lines are more likely to have been replaced already.
Here’s a C++ solution:
string selected_line;
for(size_t linenumber=0;!file.eof();linenumber++) {
string s = file.getline();
int64_t r = rand64();
r = r%linenumber;
if(r==0) {
selected_line = s;
}
}
cout << selected_line << endl;
You can read more about this here.
February 25, 2015, 5:44 pm
Serving HTTPS content with golang is pretty straight forward. You’ll need to your certificate/key pem files to ListenAndServeTLS but that’s about it. However you may also want to insure that your users always use HTTPS in which case you can also listen on port 80 and just redirect them to the HTTPS site using RedirectHandler. The example below shows how you might do this:
package main
import (
"net/http"
"net"
)
func main() {
http.Handle("/", http.FileServer(http.Dir(".")))
go func() {
err := http.ListenAndServe(":80", http.RedirectHandler("https://mywebsite.com", http.StatusFound))
if err != nil {
panic("Error: " + err.Error())
}
}()
err := http.ListenAndServeTLS(":443", "cert.pem", "key.pem", nil)
if err != nil {
panic("Error: " + err.Error())
}
}
February 24, 2015, 5:39 pm
The builtin HTTP server in the golang standard library does not serve gziped content. However you can relatively easily add a wrapper function to compress data on the fly. The best tool to do this appears to be go.httpgzip. A basic example of its usage might look like this:
import (
"github.com/daaku/go.httpgzip"
"net/http"
)
func main() {
http.Handle("/", httpgzip.NewHandler(http.FileServer(http.Dir("."))))
err := http.ListenAndServe(":80", nil)
if err != nil {
panic("Error: " + err.Error())
}
}
February 23, 2015, 5:39 pm
The function below allows you to setup a SOCKS connection in golang. You should already have connected to the SOCKS server using net.Dial. The function will then send the required header to connect to the target address/port provides in address:port format. For example:
conn, err = net.Dial("tcp", "socksproxy:8080")
err = socks_connect(conn, "hosttoconnectto:80")
You can then communicate with the target server via the SOCKS proxy.
func socks_connect(conn net.Conn, address string) (error) {
host, portstr, err := net.SplitHostPort(address)
port, err2 := strconv.Atoi(portstr)
if err2 != nil {
return errors.New("Unable to parse port")
}
version := []byte{0x04} // socks version 4
cmd := []byte{0x01} // socks stream mode
buffer := bytes.NewBuffer([]byte{})
binary.Write(buffer, binary.BigEndian, version)
binary.Write(buffer, binary.BigEndian, cmd)
binary.Write(buffer, binary.BigEndian, uint16(port))
binary.Write(buffer, binary.BigEndian, []byte{0x00, 0x00, 0x00, 0x01})
binary.Write(buffer, binary.BigEndian, []byte{0x00})
binary.Write(buffer, binary.BigEndian, []byte(host))
binary.Write(buffer, binary.BigEndian, []byte{0x00})
binary.Write(conn, binary.BigEndian, buffer.Bytes())
data := make([]byte, 8) // socks responses are 8 bytes
count, err := conn.Read(data)
if err != nil {
return errors.New("Unable to connect to socks server.")
}
if count == 0 {
return errors.New("Unable to connect to socks server.")
}
if data[1] == 0x5a { // success
return nil
}
return errors.New("Unable to connect to socks server.")
}