cancel(request) bool
        request(request) bool
        connectionFlags() string
+       close()
+       postCancel(request)
        drop()
 }
 
        )
 }
 
-func (cn *PeerConn) close() {
+func (cn *peer) close() {
        if !cn.closed.Set() {
                return
        }
+       cn.discardPieceInclination()
+       cn._pieceRequestOrder.Clear()
+       cn.peerImpl.close()
+}
+
+func (cn *PeerConn) close() {
        if cn.pex.IsEnabled() {
                cn.pex.Close()
        }
        cn.tickleWriter()
-       cn.discardPieceInclination()
-       cn._pieceRequestOrder.Clear()
        if cn.conn != nil {
                cn.conn.Close()
        }
        cn.tickleWriter()
 }
 
+func (cn *PeerConn) write(msg pp.Message) bool {
+       cn.wroteMsg(&msg)
+       cn.writeBuffer.Write(msg.MustMarshalBinary())
+       torrent.Add(fmt.Sprintf("messages filled of type %s", msg.Type.String()), 1)
+       // 64KiB, but temporarily less to work around an issue with WebRTC. TODO: Update
+       // when https://github.com/pion/datachannel/issues/59 is fixed.
+       return cn.writeBuffer.Len() < 1<<15
+}
+
 func (cn *PeerConn) requestMetadataPiece(index int) {
        eID := cn.PeerExtensionIDs[pp.ExtensionNameMetadata]
        if eID == 0 {
        cn.upload(cn.write)
 }
 
-func (cn *PeerConn) write(msg pp.Message) bool {
-       cn.wroteMsg(&msg)
-       cn.writeBuffer.Write(msg.MustMarshalBinary())
-       torrent.Add(fmt.Sprintf("messages filled of type %s", msg.Type.String()), 1)
-       // 64KiB, but temporarily less to work around an issue with WebRTC. TODO: Update
-       // when https://github.com/pion/datachannel/issues/59 is fixed.
-       return cn.writeBuffer.Len() < 1<<15
-}
-
 // Routine that writes to the peer. Some of what to write is buffered by
 // activity elsewhere in the Client, and some is determined locally when the
 // connection is writable.
        return cn.pieceInclination
 }
 
-func (cn *PeerConn) discardPieceInclination() {
+func (cn *peer) discardPieceInclination() {
        if cn.pieceInclination == nil {
                return
        }
        return true
 }
 
-func (c *PeerConn) deleteAllRequests() {
+func (c *peer) deleteAllRequests() {
        for r := range c.requests {
                c.deleteRequest(r)
        }
        c.writerCond.Broadcast()
 }
 
-func (c *PeerConn) postCancel(r request) bool {
+func (c *peer) postCancel(r request) bool {
        if !c.deleteRequest(r) {
                return false
        }
-       c.post(makeCancelMessage(r))
+       c.peerImpl.postCancel(r)
        return true
 }
 
+func (c *PeerConn) postCancel(r request) {
+       c.post(makeCancelMessage(r))
+}
+
 func (c *PeerConn) sendChunk(r request, msg func(pp.Message) bool) (more bool, err error) {
        // Count the chunk being sent, even if it isn't.
        b := make([]byte, r.Length)
 
        info  *metainfo.Info
        files *[]*File
 
+       webSeeds map[string]*peer
+
        // Active peer connections, running message stream loops. TODO: Make this
        // open (not-closed) connections only.
        conns               map[*PeerConn]struct{}
        }
        torrent.Add("deleted connections", 1)
        c.deleteAllRequests()
-       if len(t.conns) == 0 {
+       if t.numActivePeers() == 0 {
                t.assertNoPendingRequests()
        }
        return
 }
 
+func (t *Torrent) numActivePeers() (num int) {
+       t.iterPeers(func(*peer) {
+               num++
+       })
+       return
+}
+
 func (t *Torrent) assertNoPendingRequests() {
        if len(t.pendingRequests) != 0 {
                panic(t.pendingRequests)
        for pc := range t.conns {
                f(&pc.peer)
        }
+       for _, ws := range t.webSeeds {
+               f(ws)
+       }
+}
+
+func (t *Torrent) addWebSeed(url string) {
+       if _, ok := t.webSeeds[url]; ok {
+               return
+       }
+       t.webSeeds[url] = &peer{
+               peerImpl: &webSeed{},
+       }
 }
 
 func (t *Torrent) peerIsActive(p *peer) (active bool) {
 
--- /dev/null
+package torrent
+
+import (
+       "net/http"
+)
+
+type webSeed struct {
+       peer       *peer
+       httpClient *http.Client
+}
+
+func (ws *webSeed) writeInterested(interested bool) bool {
+       return true
+}
+
+func (ws *webSeed) cancel(r request) bool {
+       panic("implement me")
+}
+
+func (ws *webSeed) request(r request) bool {
+       panic("implement me")
+}
+
+func (ws *webSeed) connectionFlags() string {
+       return "WS"
+}
+
+func (ws *webSeed) drop() {
+}
+
+func (ws *webSeed) updateRequests() {
+       ws.peer.doRequestState()
+}