GithubHelp home page GithubHelp logo

gorilla-xmlrpc's Introduction

gorilla-xmlrpc

GoDoc

XML-RPC implementation for the Gorilla/RPC toolkit.

It implements both server and client.

It's built on top of gorilla/rpc package in Go(Golang) language and implements XML-RPC, according to it's specification. Unlike net/rpc from Go strlib, gorilla/rpc allows usage of HTTP POST requests for RPC.

Installation

Assuming you already imported gorilla/rpc, use the following command:

go get github.com/divan/gorilla-xmlrpc/xml

Examples

Server Example

package main

import (
    "log"
    "net/http"
    "github.com/gorilla/rpc"
    "github.com/divan/gorilla-xmlrpc/xml"
)

type HelloService struct{}

func (h *HelloService) Say(r *http.Request, args *struct{Who string}, reply *struct{Message string}) error {
    log.Println("Say", args.Who)
    reply.Message = "Hello, " + args.Who + "!"
    return nil
}

func main() {
    RPC := rpc.NewServer()
    xmlrpcCodec := xml.NewCodec()
    RPC.RegisterCodec(xmlrpcCodec, "text/xml")
    RPC.RegisterService(new(HelloService), "")
    http.Handle("/RPC2", RPC)

    log.Println("Starting XML-RPC server on localhost:1234/RPC2")
    log.Fatal(http.ListenAndServe(":1234", nil))
}

It's pretty self-explanatory and can be tested with any xmlrpc client, even raw curl request:

curl -v -X POST -H "Content-Type: text/xml" -d '<methodCall><methodName>HelloService.Say</methodName><params><param><value><string>User 1</string></value></param></params></methodCall>' http://localhost:1234/RPC2

Client Example

Implementing client is beyond the scope of this package, but with encoding/decoding handlers it should be pretty trivial. Here is an example which works with the server introduced above.

package main

import (
    "log"
    "bytes"
    "net/http"
    "github.com/divan/gorilla-xmlrpc/xml"
)

func XmlRpcCall(method string, args struct{Who string}) (reply struct{Message string}, err error) {
    buf, _ := xml.EncodeClientRequest(method, &args)

    resp, err := http.Post("http://localhost:1234/RPC2", "text/xml", bytes.NewBuffer(buf))
    if err != nil {
        return
    }
    defer resp.Body.Close()

    err = xml.DecodeClientResponse(resp.Body, &reply)
    return
}

func main() {
    reply, err := XmlRpcCall("HelloService.Say", struct{Who string}{"User 1"})
    if err != nil {
        log.Fatal(err)
    }

    log.Printf("Response: %s\n", reply.Message)
}

Implementation details

The main objective was to use standard encoding/xml package for XML marshalling/unmarshalling. Unfortunately, in current implementation there is no graceful way to implement common structre for marshal and unmarshal functions - marshalling doesn't handle interface{} types so far (though, it could be changed in the future). So, marshalling is implemented manually.

Unmarshalling code first creates temporary structure for unmarshalling XML into, then converts it into the passed variable using reflect package. If XML struct member's name is lowercased, it's first letter will be uppercased, as in Go/Gorilla field name must be exported(first-letter uppercased).

Marshalling code converts rpc directly to the string XML representation.

For the better understanding, I use terms 'rpc2xml' and 'xml2rpc' instead of 'marshal' and 'unmarshall'.

Supported types

XML-RPC Golang
int, i4 int
double float64
boolean bool
string string
dateTime.iso8601 time.Time
base64 []byte
struct struct
array []interface{}
nil nil

TODO

  • Add more corner cases tests

gorilla-xmlrpc's People

Contributors

bischoff avatar divan avatar garciaolais avatar icholy avatar kzjeef avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

gorilla-xmlrpc's Issues

Error handling at client Side

I am new to golang and xml-rpc .I am using gorilla-xmlrpc package for xmlserver and client. When Server is returning fault my client is not able to handle it. As your DecodeClientResponse function is calling ioutill.ReadAll function the response received is getting lost thus i am not able to do decode it twice.
I am attaching my server and client code.
Server Code:
type Yahoo struct {
First string
Second string
}
type YahooResp struct {
Yo int
Man string
}
type Newe struct{}

func (h *Newe) Yup(r *http.Request, recvRequest *Yahoo, respLogin *YahooResp) error {
fmt.Println(recvRequest.First)
fmt.Println(recvRequest.Second)
respLogin.Yo = 1
respLogin.Man = "response"
return nil
}

Client Code:
type Yahoo struct {
First int //changed from server so that server will return error
Second string
}
type YahooResp struct {
Yo int
Man string
}

func TestFun() {
var args Yahoo
var myfault xml.Fault
var reply YahooResp
var copyBody io.Reader
args.First = 10
args.Second = "Wewin"
buf, _ := xml.EncodeClientRequest("Newe.Yup", &args)
body := bytes.NewBuffer(buf)
fmt.Printf("data to send %s \n", string(buf))
resp, err := http.Post("http://localhost:7541/xmlrpc", "text/xml", body)
if err != nil {
return
}
defer resp.Body.Close()
err = xml.DecodeClientResponse(resp.Body, &reply)
if err != nil {
fmt.Printf("Error is %v\n", err.Error())
err = xml.DecodeClientResponse(resp.Body, &myfault)
fmt.Printf("Myfault code is %d\n", myfault.Code)
fmt.Printf("Myfault string is %s\n", myfault.String)
} else {
fmt.Println(reply.Yo)
}
return
}

Problem marshalling XML-RPC service response back to client (unless I didn't define interface correctly)

Here's the code I have:

type RunKeywordReturnValue struct{
  Return    interface{} `xml:"return"`
  Status    string      `xml:"status"`
  Output    string      `xml:"output"`
  Error     string      `xml:"error"`
  Traceback string      `xml:"traceback"`
}

func (h *RobotRemoteService) RunKeyword(r *http.Request, args *KeywordAndArgsInput, reply *RunKeywordReturnValue) error {
    //do stuff then return the results in struct below (sample static output shown):
    var retval interface{}
    retval = 42
    reply.Return = retval //truth of life
    reply.Status = "FAIL"
    reply.Output = "stdout from keyword execution gets piped into this"
    reply.Error = "gorrs not fully implemented yet, just a proof of concept design at the moment. stderr from keyword execution gets piped into this, by the way."
    reply.Traceback = "stack trace info goes here, if any..."
    return nil
}

Output should look something like this:

<methodResponse>
  <params>
    <param>
      <value><struct>
        <member>
          <name>return</name>
          <value><int>42</int></value>
        </member>
        <member>
          <name>status</name>
          <value><string>PASS</string></value>
       </member>
       <member>
         <name>output</name>
         <value><string></string></value>
       </member>
       <member>
         <name>error</name>
         <value><string></string></value>
        </member>
        <member>
          <name>traceback</name>
          <value><string></string></value>
        </member>
      </struct></value>
    </param>
  </params>
</methodResponse>

with some logging code, it looks like everything executes up to the return nil statement. But after that, the XML-RPC/RPC server part returns an fault message for the response:

<methodResponse>
  <fault>
    <value><struct>
      <member>
        <name>faultCode</name>
        <value><int>-32602</int></value>
      </member>
      <member>
        <name>faultString</name>
        <value><string>Invalid Method Parameters: fields type mismatch: string != []interface {}</string></value>
     </member>
    </struct></value>
  </fault>
</methodResponse>

what exactly might I be doing wrong in mapping the response struct, the XML-RPC service function signature, and the code that assigns values to the response in the function?

Allow overriding struct member name for XML-RPC request/response?

Say I had a struct like this:

type runKeywordReturnType struct{
  sReturn interface{}
  status string
  output string
  sError string
  traceback string
}

but that I really wanted sReturn & sError to be all lowercase w/o the prefix "s", at least when served back as XML-RPC response (from server), is there a way to do that to map some stuff from native go to XML-RPC response?

There is such an option for XML-RPC.NET (.NET library): http://xml-rpc.net/faq/xmlrpcnetfaq-2-5-0.html#1.11

where I did something similar to

[XmlRpcMember("return")] 
public int Return; 

Might something like that be available in this package or the core gorilla/rpc one? Or in native go?

Well, I've seen something like that for JSON marshalling/unmarshalling in go, e.g.:

type Coordinate struct {
    X         float64 `json:"x"`
    Y         float64 `json:"y"`
}

where in go it's in one casing for example, yet another in raw JSON. Is there similar mapping usable for this XML-RPC? Where in go native struct, it's one way, and in a different case when served back as XML-RPC output?

How to handle Array responses?

Howdy. I'm using this library to connect to an XML-RPC service that returns an array -- such as a list of records that match a query. But, I'm running in to a number of errors. Unless I'm mistaken, gorilla-xmlrpc can't handle an array response, at least not as the root level result.

Unfortunately, I'm not in control of the remote XML-RPC server, so I can't just wrap the responses into a struct. So, I really need to figure out how to make this work.

I'm not sure if this project is active or not, so I'm digging in to see if I can decipher how it's working. If you have any suggestions, or even patches to make this go, please pass them on!

Bugs in Converting RPC2XML

I was trying to supply my custom parameters to XMLRPC server running on Python, the parameters are not even converting to XML tree due to some bug. Here is the log of the process: link

xml will not handle lowercase method names

Seems like the methodname has to be uppercase and also has to be handleUSSDRequest.function instead of handleUSSDRequest?

Example below this fails

handleUSSDRequest User 1

This works

handleUSSDRequest.function User 1

XML-RPC server method arguments not parsed correctly (unless I haven't defined the interface correctly)

/* how to define go gorilla/rpc func signature if XML-RPC args is comprised as
 * 2 arguments: a string argument for actual keyword/method to execute, and
 * an array of any XML-RPC type, to be the actual args for that keyword
 * e.g. sample input
 * <methodCall><methodName>RunKeyword</methodName>
 *   <params>
 *     <param><value><string>KeywordNameToExecute</string></value></param>
 *     <param><value><array><data>
 *       <value><string>keyword_arg1</string></value>
 *       <value><string>keyword_arg2</string></value>
 *     </data></array></value></param>
 *   </params></methodCall>
 */
func (h *RobotRemoteService) RunKeyword(r *http.Request, args ...interface{}, reply *runKeywordReturnType) error {

I'm a novice in go, gorilla/rpc just states that args must be *args. In the above example, args isn't really a struct with members that can be translated to this package's XML-RPC struct. It's not quite an entire array either. The sample signature given report syntax error in my go IDE/editor (Atom).

Or is there no way to do the intended mapping mentioned?

Dependency can't be installed

I got this error while trying to install this package:

$ GOPATH=$(pwd) go get github.com/divan/gorilla-xmlrpc/xml
package code.google.com/p/go-charset/charset: unable to detect version control system for code.google.com/ path
package code.google.com/p/go-charset/data: unable to detect version control system for code.google.com/ path

The XML-RPC request parameter doesn't accept, If there is no <string> tag in the <value> tag,

I sent the xml-rpc request like this, but xml-rpc server doesn't get the request value.

<?xml version="1.0"?><methodCall><methodName>MethodName</methodName><params><param><value><struct><member><name>ParamName</name><value>ParamValue</value></member></struct></value></param></params></methodCall>

I think it caused for the following reasons

If there are no type in the tag, val doesn't set because value.Array is empty.
https://github.com/divan/gorilla-xmlrpc/blob/master/xml/xml2rpc.go#L154-L155

and, we can not reach this code.
https://github.com/divan/gorilla-xmlrpc/blob/master/xml/xml2rpc.go#L157-L163

Empty arrays issue: type mismatch: string != %!s(<nil>) or type mismatch: string != []interface {}

Hello, I'm using this library to create a Metaweblog API server for Open Live Writer. However this has some problems with the following XML-RPC request:

<?xml version="1.0" encoding="utf-8"?>
<methodCall>
 <methodName>metaWeblog.newPost</methodName>
 <params>
  <param>
   <value>
    <string>1</string>
   </value>
  </param>
  <param>
   <value>
    <string>myusername</string>
   </value>
  </param>
  <param>
   <value>
    <string>mypass123</string>
   </value>
  </param>
  <param>
   <value>
    <struct>
     <member>
      <name>title</name>
      <value>
       <string>Post Title</string>
      </value>
     </member>
     <member>
      <name>description</name>
      <value>
       <string>Post content html escaped</string>
      </value>
     </member>
     <member>
      <name>categories</name>
      <value>
       <array>
        <data /><!---  HERE IS THE PROBLEM, AN EMPTY ARRAY --->
       </array>
      </value>
     </member>
    </struct>
   </value>
  </param>
  <param>
   <value>
    <boolean>1</boolean>
   </value>
  </param>
 </params>
</methodCall>

The problem is in the ARRAY, which sometimes OLW sends as shown above <data/> when there are no categories, but when there are, it sends as follows:

...
        <data>
         <value>
          <string>Category1</string>
         </value>
         <value>
          <string>Category2</string>
         </value>
        </data>
...

So, this last one works if I use []strings not []interfaces{} as you suggest on the readme. However, if there is no categories (<data/>) it will fail returning FAULT errors of type mismatch, since it will consider it as a single string instead of empty array of strings.

So, here is that part of my code:

type Post struct {
	DateCreated atime.Time  `xml:"dateCreated"`
	Description string      `xml:"description"`
	Title       string      `xml:"title"`
	Categories  []string    `xml:"categories"` //<---  Array of strings, []interfaces{} doesn't work
	Permalink   string      `xml:"permalink"`
	PostId      interface{} `xml:"postid"`
	UserId      string      `xml:"userid"`
	WP_SLUG     string      `xml:"wp_slug"`
	MT_Excerpt  string      `xml:"mt_excerpt"`
	Link        string      `xml"link"`
...
func (h *WebService) NewPost(r *http.Request, args *struct {
	Blogid, Username, Password string
	APost                      Post
	Publish                    bool
}, reply *struct{ Data bool }) error {
	reply.Data = args.Publish
	return nil

So, Post structure is passed in args, but it fails if no categories are included.

Using []interfaces{} for Array type is not working in both cases.
[]string works when the array of categories has at least one entry, but if empty, it doesn't.
string works when the array "is empty", i.e <data/> is sent instead of values by Open Live Writer as shown above.
So I would need 2 Post structures for both scenarios, when array is empty (considered as string) and when there is actually an array (in this case considered as []string).
A function overload wouldn't be an option since go doesn't support it, and variadic is not working too.
It might be OLW request issue. But I'm curious of how to deal with a MethodCall with the same MethodName for different parameters.

I'm new to Golang, so would you be kind to tell me how to solve that issue?
Maybe I should modify xml2rpc function, but I have no clue of how to start in there.

Anyway. Thanks for this library, it gave me a good start. Now, I can use OLW with my simple test website written in Golang.

Panic when service methods args or reply are not structs

the XMLRPC spec states that params can have a scalar value, currently if a method proto looks something similar to this:

func (l *ListService) List_contents(r *http.Request, args *[]byte, reply  *struct {Message int}) error {

It panics, I have a fix, it's kind of ugly since i'm new to Go, but will submit a PR shortly.

Looking for the package owner

Hey,

I'm not using XML-RPC anymore and have no time to test proposed pull-requests.

Anyone willing to get the ownership for this package? Seems like people still use XML-RPC.

DecodeClientResponse fails to parse empty strings

package main

import (
	"bytes"
	"fmt"
	"github.com/divan/gorilla-xmlrpc/xml"
)

func main() {
	var response struct {
		Result string
	}
	responseXML := []byte("<methodResponse><params><param><value><string></string></value></param></params></methodResponse>")
	err := xml.DecodeClientResponse(bytes.NewBuffer(responseXML), &response)
	if err != nil {
		fmt.Print(err)
	} else {
		fmt.Printf("%s\n", response.Result)
	}
}

I would expect the above to output a blank line but instead it outputs:

<string></string>

Serve/define XML-RPC methods without namespacing to a class/struct?

Hi,

Great project. I'm a novice at go, and looking at your example usage in the README, as well as the unit tests for gorilla/rpc, it looks like the class/struct is prefixed as namespace to the XML-RPC method being called/requested. For my particularly use case, the RPC method names are not "prefixed" with a class/namespace, but rather being global, so just a method name to call. e.g. call "say" or "Say" instead of "HelloService.Say".

I understand namespace is useful/necessary when serving from multiple structs or packages, but in my case, it would be a single one, so there's no ambiguity. And for my use case, the "client" is expecting to make the XML-RPC call without a namespace, so I don't have leeway to accommodate namespacing in the RPC request. Is there an option or way to make the RPC call omitting the namespace, more like just use a "global" namespace? I submitted a duplicate issue to gorilla/rpc#48 in case it's really more about gorilla/rpc than your XML extension of it.

For some background/history, the XML-RPC server I intend to build is serving multiple namespaced methods via use of reflection through a single wrapper class. I've done this same thing in other XML-RPC server implementations (for other languages, e.g. Perl, PHP, Java, .NET), would like to do for go now. The server I'm trying to build is a go implementation for https://github.com/robotframework/RemoteInterface, with the Python version being the reference implementation.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.