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