File Coverage

blib/lib/Net/EPP/Frame.pm
Criterion Covered Total %
statement 33 59 55.9
branch 0 8 0.0
condition n/a
subroutine 11 17 64.7
pod 1 5 20.0
total 45 89 50.5


line stmt bran cond sub pod time code
1             package Net::EPP::Frame;
2 1     1   8 use Carp;
  1         2  
  1         58  
3 1     1   419 use Net::EPP::Frame::Command;
  1         2  
  1         44  
4 1     1   414 use Net::EPP::Frame::Greeting;
  1         9  
  1         64  
5 1     1   443 use Net::EPP::Frame::Hello;
  1         4  
  1         62  
6 1     1   6 use Net::EPP::Frame::ObjectSpec;
  1         2  
  1         26  
7 1     1   408 use Net::EPP::Frame::Response;
  1         2  
  1         69  
8 1     1   7 use POSIX qw(strftime);
  1         1  
  1         8  
9 1     1   185 use XML::LibXML;
  1         2  
  1         6  
10 1     1   189 use base qw(XML::LibXML::Document);
  1         2  
  1         521  
11 1     1   7 use vars qw($EPP_URN $SCHEMA_URI);
  1         2  
  1         50  
12 1     1   18 use strict;
  1         2  
  1         610  
13              
14             our $EPP_URN = 'urn:ietf:params:xml:ns:epp-1.0';
15             our $SCHEMA_URI = 'http://www.w3.org/2001/XMLSchema-instance';
16              
17             =pod
18              
19             =head1 NAME
20              
21             Net::EPP::Frame - An EPP XML frame system built on top of L.
22              
23             =head1 SYNOPSIS
24              
25             #!/usr/bin/perl
26             use Net::EPP::Client;
27             use Net::EPP::Frame;
28             use Net::EPP::ObjectSpec;
29             use Digest::MD5 qw(md5_hex);
30             use Time::HiRes qw(time);
31             use strict;
32              
33             #
34             # establish a connection to an EPP server:
35             #
36             my $epp = Net::EPP::Client->new(
37             host => 'epp.registry.tld',
38             port => 700,
39             ssl => 1,
40             dom => 1,
41             );
42              
43             my $greeting = $epp->connect;
44              
45             #
46             # log in:
47             #
48             my $login = Net::EPP::Frame::Command::Login->new;
49              
50             $login->clID->appendText($userid);
51             $login->pw->appendText($passwd);
52              
53             #
54             # set the client transaction ID:
55             #
56             $login->clTRID->appendText(md5_hex(Time::HiRes::time().$$));
57              
58             #
59             # check the response from the log in:
60             #
61             my $answer = $epp->request($login);
62              
63             my $result = ($answer->getElementsByTagName('result'))[0];
64             if ($result->getAttribute('code') != 1000) {
65             die("Login failed!");
66             }
67              
68             #
69             # OK, let's do a domain name check:
70             #
71             my $check = Net::EPP::Frame::Command::Check->new;
72              
73             #
74             # get the spec from L:
75             #
76             my @spec = Net::EPP::Frame::ObjectSpec->spec('domain');
77              
78             #
79             # create a domain object using the spec:
80             #
81             my $domain = $check->addObject(@spec);
82              
83             #
84             # set the domain name we want to check:
85             #
86             my $name = $check->createElement('domain:name');
87             $name->appendText('example.tld');
88              
89             #
90             # set the client transaction ID:
91             #
92             $check->clTRID->appendText(md5_hex(time().$$));
93              
94             #
95             # assemble the frame:
96             #
97             $domain->addChild($name);
98              
99             #
100             # send the request:
101             #
102             my $answer = $epp->request($check);
103              
104             # and so on...
105              
106             =head1 DESCRIPTION
107              
108             EPP is the Extensible Provisioning Protocol. EPP (defined in RFC 4930) is an
109             application layer client-server protocol for the provisioning and management of
110             objects stored in a shared central repository. Specified in XML, the protocol
111             defines generic object management operations and an extensible framework that
112             maps protocol operations to objects. As of writing, its only well-developed
113             application is the provisioning of Internet domain names, hosts, and related
114             contact details.
115              
116             EPP uses XML documents called "frames" send data to and from clients
117             and servers. This module implements a subclass of the L
118             module that simplifies the process of creation of these frames. It is designed
119             to be used alongside the L module.
120              
121             =head1 OBJECT HIERARCHY
122              
123             L
124             +----L
125             +----L
126              
127              
128             =head1 USAGE
129              
130             As a rule, you will not need to create Net::EPP::Frame objects directly.
131             Instead, you should use one of the subclasses included with the distribution.
132             The subclasses all inherit from Net::EPP::Frame.
133              
134             Net::EPP::Frame is itself a subclass of L so all the
135             methods available from that class are also available to instances of
136             Net::EPP::Frame.
137              
138             The available subclasses of Net::EPP::Frame exist to add any additional
139             elements required by the EPP specification. For example, the EloginE
140             frame must contain the EclIDE and EpwE frames, so when you
141             create a new L object, you get these already
142             defined.
143              
144             These classes also have convenience methods, so for the above example, you can
145             call the C<$login-EclID> and C<$login-Epw> methods to get the
146             L objects correesponding to those elements.
147              
148             =head2 RATIONALE
149              
150             You could just as easily construct your EPP frames from templates or just lots
151             of C calls. But using a programmatic approach such as this strongly
152             couples the validity of your XML to the validity of your program. If the
153             process by which your XML is built is broken, I. This
154             has to be a win.
155              
156             =cut
157              
158             sub new {
159 0     0 1   my ($package, $type) = @_;
160              
161 0 0         if (!$type) {
162 0           my @parts = split(/::/, $package);
163 0           $type = lc(pop(@parts));
164             }
165              
166 0 0         if ($type !~ /^(hello|greeting|command|response)$/) {
167 0           croak("'type' parameter to Net::EPP::Frame::new() must be one of: hello, greeting, command, response ('$type' given).");
168 0           return undef;
169             }
170              
171 0           my $self = $package->SUPER::new('1.0', 'UTF-8');
172 0           bless($self, $package);
173              
174 0           my $epp = $self->createElementNS($EPP_URN, 'epp');
175 0           $self->addChild($epp);
176              
177 0           my $el = $self->createElement($type);
178 0           $epp->addChild($el);
179              
180 0           $self->_addExtraElements;
181              
182 0           return $self;
183             }
184              
185       0     sub _addExtraElements {
186             }
187              
188             =pod
189              
190             =head1 ADDITIONAL METHODS
191              
192             my $str = $frame->formatTimeStamp($timestamp);
193              
194             This method returns a scalar in the required format (defined in RFC 3339). This
195             is a convenience method.
196              
197             =cut
198              
199             sub formatTimeStamp {
200 0     0 0   my ($self, $stamp) = @_;
201 0           return strftime('%Y-%m-%dT%H:%M:%S.0Z', gmtime($stamp));
202             }
203              
204             =pod
205              
206             my $node = $frame->getNode($id);
207             my $node = $frame->getNode($ns, $id);
208              
209             This is another convenience method. It uses C<$id> with the
210             I method to get a list of nodes with that element name,
211             and simply returns the first L from the list.
212              
213             If C<$ns> is provided, then I is used.
214              
215             =cut
216              
217             sub getNode {
218 0     0 0   my ($self, @args) = @_;
219 0 0         if (scalar(@args) == 2) {
    0          
220 0           return ($self->getElementsByTagNameNS(@args))[0];
221              
222             } elsif (scalar(@args) == 1) {
223 0           return ($self->getElementsByTagName($args[0]))[0];
224              
225             } else {
226 0           croak('Invalid number of arguments to getNode()');
227              
228             }
229             }
230              
231             =pod
232              
233             my $binary = $frame->header;
234              
235             Returns a scalar containing the frame length packed into binary. This is
236             only useful for low-level protocol stuff.
237              
238             =cut
239              
240             sub header {
241 0     0 0   my $self = shift;
242 0           return pack('N', length($self->toString) + 4);
243             }
244              
245             =pod
246              
247             my $data = $frame->frame;
248              
249             Returns a scalar containing the frame header (see the I method
250             above) concatenated with the XML frame itself. This is only useful for
251             low-level protocol stuff.
252              
253             =cut
254              
255             sub frame {
256 0     0 0   my $self = shift;
257 0           return $self->header.$self->toString;
258             }
259              
260             =pod
261              
262             =head1 AVAILABLE SUBCLASSES
263              
264             =over
265              
266             =item L, the base class
267              
268             =item L, for EPP client command frames
269              
270             =item L, for EPP EcheckE client commands
271              
272             =item L, for EPP EcreateE client commands
273              
274             =item L, for EPP EdeleteE client commands
275              
276             =item L, for EPP EinfoE client commands
277              
278             =item L, for EPP EloginE client commands
279              
280             =item L, for EPP ElogoutE client commands
281              
282             =item L, for EPP EpollE client commands
283              
284             =item L, for EPP ErenewE client commands
285              
286             =item L, for EPP EtransferE client commands
287              
288             =item L, for EupdateE client commands
289              
290             =item L, for EPP server greetings
291              
292             =item L, for EPP client greetings
293              
294             =item L, for EPP server response frames
295              
296             =back
297              
298             Each subclass has its own subclasses for various objects, for example L creates CcheckE> frame for domain names.
299              
300             Coverage for all combinations of command and object type is not complete, but work is ongoing.
301              
302             =cut
303              
304             1;