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

View as plain text