func getObjectsHandler(w http.ResponseWriter, req *http.Request) { if req.Method != "CONNECT" { w.Header().Set("Content-Type", "text/plain; charset=utf-8") w.WriteHeader(http.StatusMethodNotAllowed) io.WriteString(w, "405 must CONNECT\n") return } conn, bufrw, err := w.(http.Hijacker).Hijack() if err != nil { logger.Println("rpc hijacking ", req.RemoteAddr, ": ", err.Error()) return } defer conn.Close() defer bufrw.Flush() io.WriteString(conn, "HTTP/1.0 200 Connected to GetObjects RPC\n\n") var request objectserver.GetObjectsRequest var response objectserver.GetObjectsResponse if request.Exclusive { exclusive.Lock() defer exclusive.Unlock() } else { exclusive.RLock() defer exclusive.RUnlock() getSemaphore <- true defer releaseSemaphore(getSemaphore) } decoder := gob.NewDecoder(bufrw) encoder := gob.NewEncoder(bufrw) err = decoder.Decode(&request) if err != nil { response.ResponseString = err.Error() encoder.Encode(response) return } response.ObjectSizes, err = objectServer.CheckObjects(request.Hashes) if err != nil { response.ResponseString = err.Error() encoder.Encode(response) return } // First a quick check for existence. If any objects missing, fail request. for index, hash := range request.Hashes { if response.ObjectSizes[index] < 1 { response.ResponseString = fmt.Sprintf("unknown object: %x", hash) encoder.Encode(response) return } } objectsReader, err := objectServer.GetObjects(request.Hashes) if err != nil { response.ResponseString = err.Error() encoder.Encode(response) return } encoder.Encode(response) bufrw.Flush() for range request.Hashes { _, reader, err := objectsReader.NextObject() if err != nil { logger.Println(err) return } _, err = io.Copy(conn, reader) reader.Close() if err != nil { logger.Printf("Error copying:\t%s\n", err) return } } }
func (objSrv *srpcType) GetObjects(conn *srpc.Conn) error { defer conn.Flush() var request objectserver.GetObjectsRequest var response objectserver.GetObjectsResponse if request.Exclusive { exclusive.Lock() defer exclusive.Unlock() } else { exclusive.RLock() defer exclusive.RUnlock() objSrv.getSemaphore <- true defer releaseSemaphore(objSrv.getSemaphore) } decoder := gob.NewDecoder(conn) encoder := gob.NewEncoder(conn) var err error if err = decoder.Decode(&request); err != nil { response.ResponseString = err.Error() return encoder.Encode(response) } response.ObjectSizes, err = objSrv.objectServer.CheckObjects(request.Hashes) if err != nil { response.ResponseString = err.Error() return encoder.Encode(response) } // First a quick check for existence. If any objects missing, fail request. for index, hash := range request.Hashes { if response.ObjectSizes[index] < 1 { response.ResponseString = fmt.Sprintf("unknown object: %x", hash) return encoder.Encode(response) } } objectsReader, err := objSrv.objectServer.GetObjects(request.Hashes) if err != nil { response.ResponseString = err.Error() return encoder.Encode(response) } defer objectsReader.Close() if err := encoder.Encode(response); err != nil { return err } conn.Flush() for _, hash := range request.Hashes { length, reader, err := objectsReader.NextObject() if err != nil { objSrv.logger.Println(err) return err } nCopied, err := io.Copy(conn.Writer, reader) reader.Close() if err != nil { objSrv.logger.Printf("Error copying:\t%s\n", err) return err } if nCopied != int64(length) { txt := fmt.Sprintf("Expected length: %d, got: %d for: %x", length, nCopied, hash) objSrv.logger.Printf(txt) return errors.New(txt) } } objSrv.logger.Printf("GetObjects() sent: %d objects\n", len(request.Hashes)) return nil }