...
Run Format

Source file src/net/rpc/server.go

     1	// Copyright 2009 The Go Authors. All rights reserved.
     2	// Use of this source code is governed by a BSD-style
     3	// license that can be found in the LICENSE file.
     4	
     5	/*
     6		Package rpc provides access to the exported methods of an object across a
     7		network or other I/O connection.  A server registers an object, making it visible
     8		as a service with the name of the type of the object.  After registration, exported
     9		methods of the object will be accessible remotely.  A server may register multiple
    10		objects (services) of different types but it is an error to register multiple
    11		objects of the same type.
    12	
    13		Only methods that satisfy these criteria will be made available for remote access;
    14		other methods will be ignored:
    15	
    16			- the method's type is exported.
    17			- the method is exported.
    18			- the method has two arguments, both exported (or builtin) types.
    19			- the method's second argument is a pointer.
    20			- the method has return type error.
    21	
    22		In effect, the method must look schematically like
    23	
    24			func (t *T) MethodName(argType T1, replyType *T2) error
    25	
    26		where T1 and T2 can be marshaled by encoding/gob.
    27		These requirements apply even if a different codec is used.
    28		(In the future, these requirements may soften for custom codecs.)
    29	
    30		The method's first argument represents the arguments provided by the caller; the
    31		second argument represents the result parameters to be returned to the caller.
    32		The method's return value, if non-nil, is passed back as a string that the client
    33		sees as if created by errors.New.  If an error is returned, the reply parameter
    34		will not be sent back to the client.
    35	
    36		The server may handle requests on a single connection by calling ServeConn.  More
    37		typically it will create a network listener and call Accept or, for an HTTP
    38		listener, HandleHTTP and http.Serve.
    39	
    40		A client wishing to use the service establishes a connection and then invokes
    41		NewClient on the connection.  The convenience function Dial (DialHTTP) performs
    42		both steps for a raw network connection (an HTTP connection).  The resulting
    43		Client object has two methods, Call and Go, that specify the service and method to
    44		call, a pointer containing the arguments, and a pointer to receive the result
    45		parameters.
    46	
    47		The Call method waits for the remote call to complete while the Go method
    48		launches the call asynchronously and signals completion using the Call
    49		structure's Done channel.
    50	
    51		Unless an explicit codec is set up, package encoding/gob is used to
    52		transport the data.
    53	
    54		Here is a simple example.  A server wishes to export an object of type Arith:
    55	
    56			package server
    57	
    58			import "errors"
    59	
    60			type Args struct {
    61				A, B int
    62			}
    63	
    64			type Quotient struct {
    65				Quo, Rem int
    66			}
    67	
    68			type Arith int
    69	
    70			func (t *Arith) Multiply(args *Args, reply *int) error {
    71				*reply = args.A * args.B
    72				return nil
    73			}
    74	
    75			func (t *Arith) Divide(args *Args, quo *Quotient) error {
    76				if args.B == 0 {
    77					return errors.New("divide by zero")
    78				}
    79				quo.Quo = args.A / args.B
    80				quo.Rem = args.A % args.B
    81				return nil
    82			}
    83	
    84		The server calls (for HTTP service):
    85	
    86			arith := new(Arith)
    87			rpc.Register(arith)
    88			rpc.HandleHTTP()
    89			l, e := net.Listen("tcp", ":1234")
    90			if e != nil {
    91				log.Fatal("listen error:", e)
    92			}
    93			go http.Serve(l, nil)
    94	
    95		At this point, clients can see a service "Arith" with methods "Arith.Multiply" and
    96		"Arith.Divide".  To invoke one, a client first dials the server:
    97	
    98			client, err := rpc.DialHTTP("tcp", serverAddress + ":1234")
    99			if err != nil {
   100				log.Fatal("dialing:", err)
   101			}
   102	
   103		Then it can make a remote call:
   104	
   105			// Synchronous call
   106			args := &server.Args{7,8}
   107			var reply int
   108			err = client.Call("Arith.Multiply", args, &reply)
   109			if err != nil {
   110				log.Fatal("arith error:", err)
   111			}
   112			fmt.Printf("Arith: %d*%d=%d", args.A, args.B, reply)
   113	
   114		or
   115	
   116			// Asynchronous call
   117			quotient := new(Quotient)
   118			divCall := client.Go("Arith.Divide", args, quotient, nil)
   119			replyCall := <-divCall.Done	// will be equal to divCall
   120			// check errors, print, etc.
   121	
   122		A server implementation will often provide a simple, type-safe wrapper for the
   123		client.
   124	
   125		The net/rpc package is frozen and is not accepting new features.
   126	*/
   127	package rpc
   128	
   129	import (
   130		"bufio"
   131		"encoding/gob"
   132		"errors"
   133		"io"
   134		"log"
   135		"net"
   136		"net/http"
   137		"reflect"
   138		"strings"
   139		"sync"
   140		"unicode"
   141		"unicode/utf8"
   142	)
   143	
   144	const (
   145		// Defaults used by HandleHTTP
   146		DefaultRPCPath   = "/_goRPC_"
   147		DefaultDebugPath = "/debug/rpc"
   148	)
   149	
   150	// Precompute the reflect type for error. Can't use error directly
   151	// because Typeof takes an empty interface value. This is annoying.
   152	var typeOfError = reflect.TypeOf((*error)(nil)).Elem()
   153	
   154	type methodType struct {
   155		sync.Mutex // protects counters
   156		method     reflect.Method
   157		ArgType    reflect.Type
   158		ReplyType  reflect.Type
   159		numCalls   uint
   160	}
   161	
   162	type service struct {
   163		name   string                 // name of service
   164		rcvr   reflect.Value          // receiver of methods for the service
   165		typ    reflect.Type           // type of the receiver
   166		method map[string]*methodType // registered methods
   167	}
   168	
   169	// Request is a header written before every RPC call. It is used internally
   170	// but documented here as an aid to debugging, such as when analyzing
   171	// network traffic.
   172	type Request struct {
   173		ServiceMethod string   // format: "Service.Method"
   174		Seq           uint64   // sequence number chosen by client
   175		next          *Request // for free list in Server
   176	}
   177	
   178	// Response is a header written before every RPC return. It is used internally
   179	// but documented here as an aid to debugging, such as when analyzing
   180	// network traffic.
   181	type Response struct {
   182		ServiceMethod string    // echoes that of the Request
   183		Seq           uint64    // echoes that of the request
   184		Error         string    // error, if any.
   185		next          *Response // for free list in Server
   186	}
   187	
   188	// Server represents an RPC Server.
   189	type Server struct {
   190		mu         sync.RWMutex // protects the serviceMap
   191		serviceMap map[string]*service
   192		reqLock    sync.Mutex // protects freeReq
   193		freeReq    *Request
   194		respLock   sync.Mutex // protects freeResp
   195		freeResp   *Response
   196	}
   197	
   198	// NewServer returns a new Server.
   199	func NewServer() *Server {
   200		return &Server{serviceMap: make(map[string]*service)}
   201	}
   202	
   203	// DefaultServer is the default instance of *Server.
   204	var DefaultServer = NewServer()
   205	
   206	// Is this an exported - upper case - name?
   207	func isExported(name string) bool {
   208		rune, _ := utf8.DecodeRuneInString(name)
   209		return unicode.IsUpper(rune)
   210	}
   211	
   212	// Is this type exported or a builtin?
   213	func isExportedOrBuiltinType(t reflect.Type) bool {
   214		for t.Kind() == reflect.Ptr {
   215			t = t.Elem()
   216		}
   217		// PkgPath will be non-empty even for an exported type,
   218		// so we need to check the type name as well.
   219		return isExported(t.Name()) || t.PkgPath() == ""
   220	}
   221	
   222	// Register publishes in the server the set of methods of the
   223	// receiver value that satisfy the following conditions:
   224	//	- exported method of exported type
   225	//	- two arguments, both of exported type
   226	//	- the second argument is a pointer
   227	//	- one return value, of type error
   228	// It returns an error if the receiver is not an exported type or has
   229	// no suitable methods. It also logs the error using package log.
   230	// The client accesses each method using a string of the form "Type.Method",
   231	// where Type is the receiver's concrete type.
   232	func (server *Server) Register(rcvr interface{}) error {
   233		return server.register(rcvr, "", false)
   234	}
   235	
   236	// RegisterName is like Register but uses the provided name for the type
   237	// instead of the receiver's concrete type.
   238	func (server *Server) RegisterName(name string, rcvr interface{}) error {
   239		return server.register(rcvr, name, true)
   240	}
   241	
   242	func (server *Server) register(rcvr interface{}, name string, useName bool) error {
   243		server.mu.Lock()
   244		defer server.mu.Unlock()
   245		if server.serviceMap == nil {
   246			server.serviceMap = make(map[string]*service)
   247		}
   248		s := new(service)
   249		s.typ = reflect.TypeOf(rcvr)
   250		s.rcvr = reflect.ValueOf(rcvr)
   251		sname := reflect.Indirect(s.rcvr).Type().Name()
   252		if useName {
   253			sname = name
   254		}
   255		if sname == "" {
   256			s := "rpc.Register: no service name for type " + s.typ.String()
   257			log.Print(s)
   258			return errors.New(s)
   259		}
   260		if !isExported(sname) && !useName {
   261			s := "rpc.Register: type " + sname + " is not exported"
   262			log.Print(s)
   263			return errors.New(s)
   264		}
   265		if _, present := server.serviceMap[sname]; present {
   266			return errors.New("rpc: service already defined: " + sname)
   267		}
   268		s.name = sname
   269	
   270		// Install the methods
   271		s.method = suitableMethods(s.typ, true)
   272	
   273		if len(s.method) == 0 {
   274			str := ""
   275	
   276			// To help the user, see if a pointer receiver would work.
   277			method := suitableMethods(reflect.PtrTo(s.typ), false)
   278			if len(method) != 0 {
   279				str = "rpc.Register: type " + sname + " has no exported methods of suitable type (hint: pass a pointer to value of that type)"
   280			} else {
   281				str = "rpc.Register: type " + sname + " has no exported methods of suitable type"
   282			}
   283			log.Print(str)
   284			return errors.New(str)
   285		}
   286		server.serviceMap[s.name] = s
   287		return nil
   288	}
   289	
   290	// suitableMethods returns suitable Rpc methods of typ, it will report
   291	// error using log if reportErr is true.
   292	func suitableMethods(typ reflect.Type, reportErr bool) map[string]*methodType {
   293		methods := make(map[string]*methodType)
   294		for m := 0; m < typ.NumMethod(); m++ {
   295			method := typ.Method(m)
   296			mtype := method.Type
   297			mname := method.Name
   298			// Method must be exported.
   299			if method.PkgPath != "" {
   300				continue
   301			}
   302			// Method needs three ins: receiver, *args, *reply.
   303			if mtype.NumIn() != 3 {
   304				if reportErr {
   305					log.Println("method", mname, "has wrong number of ins:", mtype.NumIn())
   306				}
   307				continue
   308			}
   309			// First arg need not be a pointer.
   310			argType := mtype.In(1)
   311			if !isExportedOrBuiltinType(argType) {
   312				if reportErr {
   313					log.Println(mname, "argument type not exported:", argType)
   314				}
   315				continue
   316			}
   317			// Second arg must be a pointer.
   318			replyType := mtype.In(2)
   319			if replyType.Kind() != reflect.Ptr {
   320				if reportErr {
   321					log.Println("method", mname, "reply type not a pointer:", replyType)
   322				}
   323				continue
   324			}
   325			// Reply type must be exported.
   326			if !isExportedOrBuiltinType(replyType) {
   327				if reportErr {
   328					log.Println("method", mname, "reply type not exported:", replyType)
   329				}
   330				continue
   331			}
   332			// Method needs one out.
   333			if mtype.NumOut() != 1 {
   334				if reportErr {
   335					log.Println("method", mname, "has wrong number of outs:", mtype.NumOut())
   336				}
   337				continue
   338			}
   339			// The return type of the method must be error.
   340			if returnType := mtype.Out(0); returnType != typeOfError {
   341				if reportErr {
   342					log.Println("method", mname, "returns", returnType.String(), "not error")
   343				}
   344				continue
   345			}
   346			methods[mname] = &methodType{method: method, ArgType: argType, ReplyType: replyType}
   347		}
   348		return methods
   349	}
   350	
   351	// A value sent as a placeholder for the server's response value when the server
   352	// receives an invalid request. It is never decoded by the client since the Response
   353	// contains an error when it is used.
   354	var invalidRequest = struct{}{}
   355	
   356	func (server *Server) sendResponse(sending *sync.Mutex, req *Request, reply interface{}, codec ServerCodec, errmsg string) {
   357		resp := server.getResponse()
   358		// Encode the response header
   359		resp.ServiceMethod = req.ServiceMethod
   360		if errmsg != "" {
   361			resp.Error = errmsg
   362			reply = invalidRequest
   363		}
   364		resp.Seq = req.Seq
   365		sending.Lock()
   366		err := codec.WriteResponse(resp, reply)
   367		if debugLog && err != nil {
   368			log.Println("rpc: writing response:", err)
   369		}
   370		sending.Unlock()
   371		server.freeResponse(resp)
   372	}
   373	
   374	func (m *methodType) NumCalls() (n uint) {
   375		m.Lock()
   376		n = m.numCalls
   377		m.Unlock()
   378		return n
   379	}
   380	
   381	func (s *service) call(server *Server, sending *sync.Mutex, mtype *methodType, req *Request, argv, replyv reflect.Value, codec ServerCodec) {
   382		mtype.Lock()
   383		mtype.numCalls++
   384		mtype.Unlock()
   385		function := mtype.method.Func
   386		// Invoke the method, providing a new value for the reply.
   387		returnValues := function.Call([]reflect.Value{s.rcvr, argv, replyv})
   388		// The return value for the method is an error.
   389		errInter := returnValues[0].Interface()
   390		errmsg := ""
   391		if errInter != nil {
   392			errmsg = errInter.(error).Error()
   393		}
   394		server.sendResponse(sending, req, replyv.Interface(), codec, errmsg)
   395		server.freeRequest(req)
   396	}
   397	
   398	type gobServerCodec struct {
   399		rwc    io.ReadWriteCloser
   400		dec    *gob.Decoder
   401		enc    *gob.Encoder
   402		encBuf *bufio.Writer
   403		closed bool
   404	}
   405	
   406	func (c *gobServerCodec) ReadRequestHeader(r *Request) error {
   407		return c.dec.Decode(r)
   408	}
   409	
   410	func (c *gobServerCodec) ReadRequestBody(body interface{}) error {
   411		return c.dec.Decode(body)
   412	}
   413	
   414	func (c *gobServerCodec) WriteResponse(r *Response, body interface{}) (err error) {
   415		if err = c.enc.Encode(r); err != nil {
   416			if c.encBuf.Flush() == nil {
   417				// Gob couldn't encode the header. Should not happen, so if it does,
   418				// shut down the connection to signal that the connection is broken.
   419				log.Println("rpc: gob error encoding response:", err)
   420				c.Close()
   421			}
   422			return
   423		}
   424		if err = c.enc.Encode(body); err != nil {
   425			if c.encBuf.Flush() == nil {
   426				// Was a gob problem encoding the body but the header has been written.
   427				// Shut down the connection to signal that the connection is broken.
   428				log.Println("rpc: gob error encoding body:", err)
   429				c.Close()
   430			}
   431			return
   432		}
   433		return c.encBuf.Flush()
   434	}
   435	
   436	func (c *gobServerCodec) Close() error {
   437		if c.closed {
   438			// Only call c.rwc.Close once; otherwise the semantics are undefined.
   439			return nil
   440		}
   441		c.closed = true
   442		return c.rwc.Close()
   443	}
   444	
   445	// ServeConn runs the server on a single connection.
   446	// ServeConn blocks, serving the connection until the client hangs up.
   447	// The caller typically invokes ServeConn in a go statement.
   448	// ServeConn uses the gob wire format (see package gob) on the
   449	// connection. To use an alternate codec, use ServeCodec.
   450	func (server *Server) ServeConn(conn io.ReadWriteCloser) {
   451		buf := bufio.NewWriter(conn)
   452		srv := &gobServerCodec{
   453			rwc:    conn,
   454			dec:    gob.NewDecoder(conn),
   455			enc:    gob.NewEncoder(buf),
   456			encBuf: buf,
   457		}
   458		server.ServeCodec(srv)
   459	}
   460	
   461	// ServeCodec is like ServeConn but uses the specified codec to
   462	// decode requests and encode responses.
   463	func (server *Server) ServeCodec(codec ServerCodec) {
   464		sending := new(sync.Mutex)
   465		for {
   466			service, mtype, req, argv, replyv, keepReading, err := server.readRequest(codec)
   467			if err != nil {
   468				if debugLog && err != io.EOF {
   469					log.Println("rpc:", err)
   470				}
   471				if !keepReading {
   472					break
   473				}
   474				// send a response if we actually managed to read a header.
   475				if req != nil {
   476					server.sendResponse(sending, req, invalidRequest, codec, err.Error())
   477					server.freeRequest(req)
   478				}
   479				continue
   480			}
   481			go service.call(server, sending, mtype, req, argv, replyv, codec)
   482		}
   483		codec.Close()
   484	}
   485	
   486	// ServeRequest is like ServeCodec but synchronously serves a single request.
   487	// It does not close the codec upon completion.
   488	func (server *Server) ServeRequest(codec ServerCodec) error {
   489		sending := new(sync.Mutex)
   490		service, mtype, req, argv, replyv, keepReading, err := server.readRequest(codec)
   491		if err != nil {
   492			if !keepReading {
   493				return err
   494			}
   495			// send a response if we actually managed to read a header.
   496			if req != nil {
   497				server.sendResponse(sending, req, invalidRequest, codec, err.Error())
   498				server.freeRequest(req)
   499			}
   500			return err
   501		}
   502		service.call(server, sending, mtype, req, argv, replyv, codec)
   503		return nil
   504	}
   505	
   506	func (server *Server) getRequest() *Request {
   507		server.reqLock.Lock()
   508		req := server.freeReq
   509		if req == nil {
   510			req = new(Request)
   511		} else {
   512			server.freeReq = req.next
   513			*req = Request{}
   514		}
   515		server.reqLock.Unlock()
   516		return req
   517	}
   518	
   519	func (server *Server) freeRequest(req *Request) {
   520		server.reqLock.Lock()
   521		req.next = server.freeReq
   522		server.freeReq = req
   523		server.reqLock.Unlock()
   524	}
   525	
   526	func (server *Server) getResponse() *Response {
   527		server.respLock.Lock()
   528		resp := server.freeResp
   529		if resp == nil {
   530			resp = new(Response)
   531		} else {
   532			server.freeResp = resp.next
   533			*resp = Response{}
   534		}
   535		server.respLock.Unlock()
   536		return resp
   537	}
   538	
   539	func (server *Server) freeResponse(resp *Response) {
   540		server.respLock.Lock()
   541		resp.next = server.freeResp
   542		server.freeResp = resp
   543		server.respLock.Unlock()
   544	}
   545	
   546	func (server *Server) readRequest(codec ServerCodec) (service *service, mtype *methodType, req *Request, argv, replyv reflect.Value, keepReading bool, err error) {
   547		service, mtype, req, keepReading, err = server.readRequestHeader(codec)
   548		if err != nil {
   549			if !keepReading {
   550				return
   551			}
   552			// discard body
   553			codec.ReadRequestBody(nil)
   554			return
   555		}
   556	
   557		// Decode the argument value.
   558		argIsValue := false // if true, need to indirect before calling.
   559		if mtype.ArgType.Kind() == reflect.Ptr {
   560			argv = reflect.New(mtype.ArgType.Elem())
   561		} else {
   562			argv = reflect.New(mtype.ArgType)
   563			argIsValue = true
   564		}
   565		// argv guaranteed to be a pointer now.
   566		if err = codec.ReadRequestBody(argv.Interface()); err != nil {
   567			return
   568		}
   569		if argIsValue {
   570			argv = argv.Elem()
   571		}
   572	
   573		replyv = reflect.New(mtype.ReplyType.Elem())
   574		return
   575	}
   576	
   577	func (server *Server) readRequestHeader(codec ServerCodec) (service *service, mtype *methodType, req *Request, keepReading bool, err error) {
   578		// Grab the request header.
   579		req = server.getRequest()
   580		err = codec.ReadRequestHeader(req)
   581		if err != nil {
   582			req = nil
   583			if err == io.EOF || err == io.ErrUnexpectedEOF {
   584				return
   585			}
   586			err = errors.New("rpc: server cannot decode request: " + err.Error())
   587			return
   588		}
   589	
   590		// We read the header successfully. If we see an error now,
   591		// we can still recover and move on to the next request.
   592		keepReading = true
   593	
   594		dot := strings.LastIndex(req.ServiceMethod, ".")
   595		if dot < 0 {
   596			err = errors.New("rpc: service/method request ill-formed: " + req.ServiceMethod)
   597			return
   598		}
   599		serviceName := req.ServiceMethod[:dot]
   600		methodName := req.ServiceMethod[dot+1:]
   601	
   602		// Look up the request.
   603		server.mu.RLock()
   604		service = server.serviceMap[serviceName]
   605		server.mu.RUnlock()
   606		if service == nil {
   607			err = errors.New("rpc: can't find service " + req.ServiceMethod)
   608			return
   609		}
   610		mtype = service.method[methodName]
   611		if mtype == nil {
   612			err = errors.New("rpc: can't find method " + req.ServiceMethod)
   613		}
   614		return
   615	}
   616	
   617	// Accept accepts connections on the listener and serves requests
   618	// for each incoming connection. Accept blocks until the listener
   619	// returns a non-nil error. The caller typically invokes Accept in a
   620	// go statement.
   621	func (server *Server) Accept(lis net.Listener) {
   622		for {
   623			conn, err := lis.Accept()
   624			if err != nil {
   625				log.Print("rpc.Serve: accept:", err.Error())
   626				return
   627			}
   628			go server.ServeConn(conn)
   629		}
   630	}
   631	
   632	// Register publishes the receiver's methods in the DefaultServer.
   633	func Register(rcvr interface{}) error { return DefaultServer.Register(rcvr) }
   634	
   635	// RegisterName is like Register but uses the provided name for the type
   636	// instead of the receiver's concrete type.
   637	func RegisterName(name string, rcvr interface{}) error {
   638		return DefaultServer.RegisterName(name, rcvr)
   639	}
   640	
   641	// A ServerCodec implements reading of RPC requests and writing of
   642	// RPC responses for the server side of an RPC session.
   643	// The server calls ReadRequestHeader and ReadRequestBody in pairs
   644	// to read requests from the connection, and it calls WriteResponse to
   645	// write a response back. The server calls Close when finished with the
   646	// connection. ReadRequestBody may be called with a nil
   647	// argument to force the body of the request to be read and discarded.
   648	type ServerCodec interface {
   649		ReadRequestHeader(*Request) error
   650		ReadRequestBody(interface{}) error
   651		// WriteResponse must be safe for concurrent use by multiple goroutines.
   652		WriteResponse(*Response, interface{}) error
   653	
   654		Close() error
   655	}
   656	
   657	// ServeConn runs the DefaultServer on a single connection.
   658	// ServeConn blocks, serving the connection until the client hangs up.
   659	// The caller typically invokes ServeConn in a go statement.
   660	// ServeConn uses the gob wire format (see package gob) on the
   661	// connection. To use an alternate codec, use ServeCodec.
   662	func ServeConn(conn io.ReadWriteCloser) {
   663		DefaultServer.ServeConn(conn)
   664	}
   665	
   666	// ServeCodec is like ServeConn but uses the specified codec to
   667	// decode requests and encode responses.
   668	func ServeCodec(codec ServerCodec) {
   669		DefaultServer.ServeCodec(codec)
   670	}
   671	
   672	// ServeRequest is like ServeCodec but synchronously serves a single request.
   673	// It does not close the codec upon completion.
   674	func ServeRequest(codec ServerCodec) error {
   675		return DefaultServer.ServeRequest(codec)
   676	}
   677	
   678	// Accept accepts connections on the listener and serves requests
   679	// to DefaultServer for each incoming connection.
   680	// Accept blocks; the caller typically invokes it in a go statement.
   681	func Accept(lis net.Listener) { DefaultServer.Accept(lis) }
   682	
   683	// Can connect to RPC service using HTTP CONNECT to rpcPath.
   684	var connected = "200 Connected to Go RPC"
   685	
   686	// ServeHTTP implements an http.Handler that answers RPC requests.
   687	func (server *Server) ServeHTTP(w http.ResponseWriter, req *http.Request) {
   688		if req.Method != "CONNECT" {
   689			w.Header().Set("Content-Type", "text/plain; charset=utf-8")
   690			w.WriteHeader(http.StatusMethodNotAllowed)
   691			io.WriteString(w, "405 must CONNECT\n")
   692			return
   693		}
   694		conn, _, err := w.(http.Hijacker).Hijack()
   695		if err != nil {
   696			log.Print("rpc hijacking ", req.RemoteAddr, ": ", err.Error())
   697			return
   698		}
   699		io.WriteString(conn, "HTTP/1.0 "+connected+"\n\n")
   700		server.ServeConn(conn)
   701	}
   702	
   703	// HandleHTTP registers an HTTP handler for RPC messages on rpcPath,
   704	// and a debugging handler on debugPath.
   705	// It is still necessary to invoke http.Serve(), typically in a go statement.
   706	func (server *Server) HandleHTTP(rpcPath, debugPath string) {
   707		http.Handle(rpcPath, server)
   708		http.Handle(debugPath, debugHTTP{server})
   709	}
   710	
   711	// HandleHTTP registers an HTTP handler for RPC messages to DefaultServer
   712	// on DefaultRPCPath and a debugging handler on DefaultDebugPath.
   713	// It is still necessary to invoke http.Serve(), typically in a go statement.
   714	func HandleHTTP() {
   715		DefaultServer.HandleHTTP(DefaultRPCPath, DefaultDebugPath)
   716	}
   717	

View as plain text